15#include "llvm/ADT/MapVector.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/TypeSwitch.h"
19#include "llvm/Support/Mutex.h"
20#include "llvm/Support/PrettyStackTrace.h"
21#include "llvm/Support/Regex.h"
22#include "llvm/Support/Signals.h"
23#include "llvm/Support/SourceMgr.h"
24#include "llvm/Support/SourceMgrDiagnosticVerifier.h"
25#include "llvm/Support/raw_ostream.h"
50 reinterpret_cast<const void *
>(
opaqueVal));
94 auto strRef = val.toStringRef(data);
98 strings.push_back(std::unique_ptr<
char[]>(
new char[strRef.size()]));
99 memcpy(&strings.back()[0], strRef.data(), strRef.size());
101 return StringRef(&strings.back()[0], strRef.size());
150 llvm::raw_string_ostream os(
str);
154 if (
str.find(
'\n') != std::string::npos)
162 llvm::raw_string_ostream os(
str);
169 std::optional<int64_t> messagePartIndex)
const {
170 if (!messagePartIndex.has_value()) {
176 assert(0 <= *messagePartIndex &&
177 *messagePartIndex <=
static_cast<int64_t>(messagePartEnds.size()));
178 size_t argumentStart =
179 *messagePartIndex == 0 ? 0 : messagePartEnds[*messagePartIndex - 1];
181 *messagePartIndex ==
static_cast<int64_t>(messagePartEnds.size())
183 : messagePartEnds[*messagePartIndex];
192 llvm::raw_string_ostream os(
str);
200 size_t numMessageParts = messagePartEnds.size();
204 if (messagePartEnds.empty() || messagePartEnds.back() != arguments.size())
206 for (
size_t i = 0; i < numMessageParts; ++i) {
208 llvm::raw_string_ostream os(
str);
221 "cannot attach a note to a note");
230 return *notes.back();
234Diagnostic::operator LogicalResult()
const {
return failure(); }
238 if (arguments.empty())
240 if (!messagePartEnds.empty() && messagePartEnds.back() == arguments.size())
242 messagePartEnds.push_back(arguments.size());
251InFlightDiagnostic::operator LogicalResult()
const {
252 return failure(isActive());
260 owner->emit(std::move(*
impl));
298 llvm::sys::SmartScopedLock<true> lock(
mutex);
303 for (
auto &handlerIt : llvm::reverse(
handlers))
304 if (succeeded(handlerIt.second(
diag)))
311 auto &os = llvm::errs();
312 if (!llvm::isa<UnknownLoc>(
diag.getLocation()))
313 os <<
diag.getLocation() <<
": ";
332 llvm::sys::SmartScopedLock<true> lock(
impl->mutex);
333 auto uniqueID =
impl->uniqueHandlerId++;
334 impl->handlers.insert({uniqueID, std::move(handler)});
340 llvm::sys::SmartScopedLock<true> lock(
impl->mutex);
341 impl->handlers.erase(handlerID);
348 "notes should not be emitted directly");
359 auto diag = diagEngine.emit(location, severity);
360 if (!message.isTriviallyEmpty())
367 llvm::raw_string_ostream stream(bt);
368 llvm::sys::PrintStackTrace(stream);
371 diag.attachNote() <<
"diagnostic emitted with trace:\n" << bt;
405 ctx->getDiagEngine().eraseHandler(handlerID);
417 StringRef filename) {
421 return bufferIt->second;
424 for (
unsigned i = 1, e = mgr.getNumBuffers() + 1; i != e; ++i) {
425 auto *buf = mgr.getMemoryBuffer(i);
426 if (buf->getBufferIdentifier() == filename)
432 unsigned id = mgr.AddIncludeFile(std::string(filename), SMLoc(), ignored);
445 if (isa<NameLoc>(loc))
447 if (
auto callLoc = dyn_cast<CallSiteLoc>(loc))
449 if (isa<FusedLoc>(loc)) {
450 for (
auto subLoc : cast<FusedLoc>(loc).getLocations()) {
464 return llvm::SourceMgr::DK_Note;
466 return llvm::SourceMgr::DK_Warning;
468 return llvm::SourceMgr::DK_Error;
470 return llvm::SourceMgr::DK_Remark;
472 llvm_unreachable(
"Unknown DiagnosticSeverity");
493 bool displaySourceLine) {
500 llvm::raw_string_ostream strOS(str);
501 if (!llvm::isa<UnknownLoc>(loc))
502 strOS << loc <<
": ";
509 if (displaySourceLine) {
510 auto smloc = convertLocToSMLoc(fileLoc);
519 llvm::raw_string_ostream locOS(locStr);
520 locOS << fileLoc.getFilename().getValue() <<
":" << fileLoc.getLine() <<
":"
521 << fileLoc.getColumn();
529 auto addLocToStack = [&](
Location loc, StringRef locContext) {
530 if (std::optional<Location> showableLoc = findLocToShow(loc))
531 locationStack.emplace_back(*showableLoc, locContext);
536 addLocToStack(loc, {});
542 loc = callLoc->getCaller();
543 for (
unsigned curDepth = 0; curDepth < callStackLimit; ++curDepth) {
544 addLocToStack(loc,
"called from");
546 loc = callLoc->getCaller();
553 if (locationStack.empty()) {
554 for (
const std::string &str :
diag.strs())
559 for (
const std::string &str :
diag.strs())
561 for (
auto &it : llvm::drop_begin(locationStack))
567 for (
auto ¬e :
diag.getNotes()) {
568 emitDiagnostic(note.getLocation(), note.str(), note.getSeverity(),
569 loc != note.getLocation());
570 loc = note.getLocation();
575 callStackLimit = limit;
579const llvm::MemoryBuffer *
581 if (
unsigned id =
impl->getSourceMgrBufferIDForFile(
mgr, filename))
582 return mgr.getMemoryBuffer(
id);
586std::optional<Location>
587SourceMgrDiagnosticHandler::findLocToShow(
Location loc) {
595 .Case([&](CallSiteLoc callLoc) -> std::optional<Location> {
598 return findLocToShow(callLoc.getCallee());
600 .Case([&](
FileLineColLoc) -> std::optional<Location> {
return loc; })
601 .Case([&](FusedLoc fusedLoc) -> std::optional<Location> {
604 for (Location childLoc : fusedLoc.getLocations())
605 if (std::optional<Location> showableLoc = findLocToShow(childLoc))
609 .Case([&](NameLoc nameLoc) -> std::optional<Location> {
610 return findLocToShow(nameLoc.getChildLoc());
612 .Case([&](OpaqueLoc opaqueLoc) -> std::optional<Location> {
614 return findLocToShow(opaqueLoc.getFallbackLocation());
616 .Case([](UnknownLoc) -> std::optional<Location> {
624SMLoc SourceMgrDiagnosticHandler::convertLocToSMLoc(
FileLineColLoc loc) {
630 unsigned bufferId = impl->getSourceMgrBufferIDForFile(
mgr, loc.
getFilename());
669 llvm_unreachable(
"Unknown DiagnosticSeverity");
678 for (
unsigned i = 0, e =
mgr.getNumBuffers(); i != e; ++i)
679 (
void)
impl->verifier.computeExpectedDiags(out,
mgr,
680 mgr.getMemoryBuffer(i + 1));
704std::unique_ptr<ScopedDiagnosticHandler>
706 return std::make_unique<ScopedDiagnosticHandler>(
711void SourceMgrDiagnosticVerifierHandler::process(
Diagnostic &
diag) {
712 for (
const std::string &str :
diag.strs())
713 process(
diag.getLocation(), str,
diag.getSeverity());
714 for (
auto ¬e :
diag.getNotes())
719void SourceMgrDiagnosticVerifierHandler::process(
LocationAttr loc,
723 const llvm::MemoryBuffer *buf =
727 using MatchResult = llvm::SourceMgrDiagnosticVerifier::MatchResult;
730 fileLoc ? fileLoc.
getLine() : 0, msg, reportUnexpected);
731 if (
result == MatchResult::Unexpected)
792 llvm::sys::SmartScopedLock<true> lock(
mutex);
801 uint64_t tid = llvm::get_threadid();
802 llvm::sys::SmartScopedLock<true> lock(
mutex);
821 return context->getDiagEngine().emit(std::move(
diag));
848 uint64_t tid = llvm::get_threadid();
849 llvm::sys::SmartScopedLock<true> lock(
mutex);
860 uint64_t tid = llvm::get_threadid();
861 llvm::sys::SmartScopedLock<true> lock(
mutex);
871 os <<
"In-Flight Diagnostics:\n";
877 if (!llvm::isa<UnknownLoc>(
diag.getLocation()))
878 os <<
diag.getLocation() <<
": ";
879 switch (
diag.getSeverity()) {
929 impl->setOrderIDForThread(orderID);
935 impl->eraseOrderIDForThread();
static OpPrintingFlags adjustPrintingFlags(OpPrintingFlags flags, DiagnosticSeverity severity)
Adjusts operation printing flags used in diagnostics for the given severity level.
static StringRef twineToStrRef(const Twine &val, SmallVectorImpl< std::unique_ptr< char[]> > &strings)
Convert a Twine to a StringRef.
static InFlightDiagnostic emitDiag(Location location, DiagnosticSeverity severity, const Twine &message)
Helper function used to emit a diagnostic with an optionally empty twine message.
static StringRef getDiagKindStr(DiagnosticSeverity kind)
Given a diagnostic kind, return a human readable string for it.
static std::optional< CallSiteLoc > getCallSiteLoc(Location loc)
Return a processable CallSiteLoc from the given location.
static llvm::SourceMgr::DiagKind getDiagKind(DiagnosticSeverity kind)
Given a diagnostic kind, returns the LLVM DiagKind.
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
MLIRContext * getContext() const
Return the context this attribute belongs to.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
A variant type that holds a single argument for a diagnostic.
DiagnosticArgumentKind
Enum that represents the different kinds of diagnostic arguments supported.
StringRef getAsString() const
Returns this argument as a string.
double getAsDouble() const
Returns this argument as a double.
DiagnosticArgument(Attribute attr)
Note: The constructors below are only exposed due to problems accessing constructors from type traits...
Type getAsType() const
Returns this argument as a Type.
int64_t getAsInteger() const
Returns this argument as a signed integer.
DiagnosticArgumentKind getKind() const
Returns the kind of this argument.
Attribute getAsAttribute() const
Returns this argument as an Attribute.
void print(raw_ostream &os) const
Outputs this argument to a stream.
uint64_t getAsUnsigned() const
Returns this argument as an unsigned integer.
uint64_t HandlerID
A handle to a specific registered handler object.
InFlightDiagnostic emit(Location loc, DiagnosticSeverity severity)
Create a new inflight diagnostic with the given location and severity.
void eraseHandler(HandlerID id)
Erase the registered diagnostic handler with the given identifier.
llvm::unique_function< LogicalResult(Diagnostic &)> HandlerTy
The handler type for MLIR diagnostics.
HandlerID registerHandler(HandlerTy handler)
Register a new handler for diagnostics to the engine.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
std::string str() const
Converts the diagnostic to a string, concatenating all the parts if there are multiples.
void startNewMessagePart()
Starts a new message part.
SmallVector< std::string > strs() const
Converts each message part to a separate string.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
MutableArrayRef< DiagnosticArgument > getArguments()
Returns the current list of diagnostic arguments.
Diagnostic(Location loc, DiagnosticSeverity severity)
std::enable_if_t<!std::is_convertible< Arg, StringRef >::value &&std::is_constructible< DiagnosticArgument, Arg >::value, Diagnostic & > operator<<(Arg &&val)
Stream operator for inserting new diagnostic arguments.
void print(raw_ostream &os, std::optional< int64_t > messagePartIndex=std::nullopt) const
Outputs this diagnostic to a stream.
Diagnostic & appendOp(Operation &op, const OpPrintingFlags &flags)
Append an operation with the given printing flags.
An instance of this location represents a tuple of file, line number, and column number.
StringAttr getFilename() const
unsigned getColumn() const
This class represents a diagnostic that is inflight and set to be reported.
void report()
Reports the diagnostic to the engine.
void abandon()
Abandons this diagnostic so that it will no longer be reported.
Location objects represent source locations information in MLIR.
T findInstanceOf()
Return an instance of the given location type if one is nested under the current location.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
bool shouldPrintStackTraceOnDiagnostic()
Return true if we should attach the current stacktrace to diagnostics when emitted.
DiagnosticEngine & getDiagEngine()
Returns the diagnostic engine for this context.
Set of flags used to control the behavior of the various IR print methods (e.g.
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Operation * getOperation() const
OpPrintingFlags & flags()
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
void eraseOrderIDForThread()
Remove the order id for the current thread.
~ParallelDiagnosticHandler()
ParallelDiagnosticHandler(MLIRContext *ctx)
void setOrderIDForThread(size_t orderID)
Set the order id for the current thread.
~ScopedDiagnosticHandler()
ScopedDiagnosticHandler(MLIRContext *ctx)
void setHandler(FuncTy &&handler)
Set the handler to manage via RAII.
void setCallStackLimit(unsigned limit)
Set the maximum depth that a call stack will be printed. Defaults to 10.
void emitDiagnostic(Location loc, Twine message, DiagnosticSeverity kind, bool displaySourceLine=true)
Emit the given diagnostic information with the held source manager.
raw_ostream & os
The output stream to use when printing diagnostics.
SourceMgrDiagnosticHandler(llvm::SourceMgr &mgr, MLIRContext *ctx, raw_ostream &os, ShouldShowLocFn &&shouldShowLocFn={})
~SourceMgrDiagnosticHandler()
ShouldShowLocFn shouldShowLocFn
A functor used when determining if a location for a diagnostic should be shown.
const llvm::MemoryBuffer * getBufferForFile(StringRef filename)
Get a memory buffer for the given file, or nullptr if no file is available.
llvm::SourceMgr & mgr
The source manager that we are wrapping.
llvm::unique_function< bool(Location)> ShouldShowLocFn
This type represents a functor used to filter out locations when printing a diagnostic.
~SourceMgrDiagnosticVerifierHandler()
SourceMgrDiagnosticVerifierHandler(llvm::SourceMgr &srcMgr, MLIRContext *ctx, raw_ostream &out, Level level=Level::All)
std::unique_ptr< ScopedDiagnosticHandler > registerInContext(MLIRContext *ctx)
Register this handler with ctx and return a scoped registration.
LogicalResult verify()
Returns the status of the handler and verifies that all expected diagnostics were emitted.
static Type getFromOpaquePointer(const void *pointer)
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void print(raw_ostream &os) const
The OpAsmOpInterface, see OpAsmInterface.td for more details.
constexpr unsigned kMaxThreadOrderEntries
How many nested parallel loops one thread tracks without a lock.
static LLVM_THREAD_LOCAL ThreadOrderEntry threadOrderStack[kMaxThreadOrderEntries]
The order ids for the current thread, one entry per enclosing parallel loop, innermost last.
static LLVM_THREAD_LOCAL unsigned threadOrderDepth
static std::atomic< uint64_t > nextHandlerUniqueID
Unique ids for parallel diagnostic handlers, so the thread-local slot below can name a handler withou...
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
DiagnosticSeverity
Defines the different supported severity of a diagnostic.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
llvm::TypeSwitch< T, ResultT > TypeSwitch
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
DiagnosticEngine::HandlerID uniqueHandlerId
This is a unique identifier counter for diagnostic handlers in the context.
llvm::sys::SmartMutex< true > mutex
A mutex to ensure that diagnostics emission is thread-safe.
void emit(Diagnostic &&diag)
Emit a diagnostic using the registered issue handle if present, or with the default behavior if not.
llvm::SmallMapVector< DiagnosticEngine::HandlerID, DiagnosticEngine::HandlerTy, 2 > handlers
These are the handlers used to report diagnostics.
size_t id
The id for this diagnostic, this is used for ordering.
bool operator<(const ThreadDiagnostic &rhs) const
ThreadDiagnostic(size_t id, Diagnostic diag)
Diagnostic diag
The diagnostic.
void print(raw_ostream &os) const override
Dump the current diagnostics that were inflight.
const uint64_t handlerUniqueID
Unique id naming this handler in the thread-local order-id stack.
MLIRContext * context
The context to emit the diagnostics to.
ParallelDiagnosticHandlerImpl(MLIRContext *ctx)
~ParallelDiagnosticHandlerImpl() override
void emitDiagnostics(llvm::function_ref< void(Diagnostic &)> emitFn) const
Utility method to emit any held diagnostics.
DiagnosticEngine::HandlerID handlerID
The unique id for the parallel handler.
DenseMap< uint64_t, size_t > threadToOrderID
Order ids, keyed by thread id, for threads nested past what the thread-local stack holds: more enclos...
void setOrderIDForThread(size_t orderID)
Set the order id for the current thread.
std::vector< ThreadDiagnostic > diagnostics
An unordered list of diagnostics that were emitted.
void eraseOrderIDForThread()
Remove the order id for the current thread.
llvm::sys::SmartMutex< true > mutex
A smart mutex to lock access to the internal state.
llvm::StringMap< unsigned > filenameToBufId
Mapping between file name and buffer ID's.
unsigned getSourceMgrBufferIDForFile(llvm::SourceMgr &mgr, StringRef filename)
Return the SrcManager buffer id for the specified file, or zero if none can be found.
SourceMgrDiagnosticVerifierHandler::Level level
Verification level.
SourceMgrDiagnosticVerifierHandlerImpl(SourceMgrDiagnosticVerifierHandler::Level level)
llvm::SourceMgrDiagnosticVerifier verifier
The generic SourceMgr-based verifier core that this handler delegates scanning and matching of 'expec...
One entry of the thread-local nesting stack: the handler an element belongs to and its order id.