Skip to content

Commit

Permalink
work towards renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
jroesch committed Aug 25, 2020
1 parent e440027 commit df57f66
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 95 deletions.
43 changes: 38 additions & 5 deletions include/tvm/ir/diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define TVM_IR_DIAGNOSTIC_H_

#include <tvm/ir/span.h>
#include <tvm/ir/module.h>
#include <tvm/parser/source_map.h>
#include <tvm/runtime/container.h>
#include <tvm/runtime/object.h>
Expand All @@ -46,7 +47,7 @@ namespace tvm {
using tvm::parser::SourceMap;

static const char* kTVM_INTERNAL_ERROR_MESSAGE = "An internal invariant was violated during the execution of TVM" \
"please read TVM's error reporting guidelines at discuss.tvm.ai";
"please read TVM's error reporting guidelines at discuss.tvm.ai/thread";

static const char* kINDENT = " ";

Expand Down Expand Up @@ -183,10 +184,11 @@ class DiagnosticContextNode : public Object {
SourceMap source_map;

/*! \brief The set of diagnostics to report. */
std::vector<Diagnostic> diagnostics;
Array<Diagnostic> diagnostics;

void VisitAttrs(AttrVisitor* v) {
v->Visit("source_map", &source_map);
v->Visit("diagnostics", &diagnostics);
}

bool SEqualReduce(const DiagnosticContextNode* other, SEqualReducer equal) const {
Expand All @@ -197,17 +199,18 @@ class DiagnosticContextNode : public Object {
TVM_DECLARE_FINAL_OBJECT_INFO(DiagnosticContextNode, Object);
};

class DiagnosticRenderer;

class DiagnosticContext : public ObjectRef {
public:
TVM_DLL DiagnosticContext(const SourceMap& source_map);

/*! \brief Emit a diagnostic. */
void Emit(const Diagnostic& diagnostic);

/*! \brief Emit a diagnostic. */
void EmitFatal(const Diagnostic& diagnostic);

void Render(std::ostream& ostream);
/*! \brief Render the errors and raise a DiagnosticError exception. */
void Render(const DiagnosticRenderer& renderer);

DiagnosticContextNode* operator->() {
CHECK(get() != nullptr);
Expand All @@ -217,5 +220,35 @@ class DiagnosticContext : public ObjectRef {
TVM_DEFINE_OBJECT_REF_METHODS(DiagnosticContext, ObjectRef, DiagnosticContextNode);
};

/*! \brief Display diagnostics in a given display format.
*
* A diagnostic renderer is responsible for converting the
* raw diagnostics into consumable output.
*
* For example the terminal renderer will render a sequence
* of compiler diagnostics to std::out and std::err in
* a human readable form.
*/
class DiagnosticRenderer {
public:
IRModule module;

DiagnosticRenderer(const IRModule& mod)
module(mod) {}

virtual void Render(const DiagnosticContext& ctx) = 0;
};

class TerminalRenderer : public DiagnosticRenderer {
IRModule module;
DiagnosticContext ctx;
std::ostream& ostream;

TerminalRenderer(const IRModule& mod, std::ostream& ostream) :
DiagnosticRenderer(mod), ostream(ostream) {}

void Render(const DiagnosticContext& ctx) override;
};

} // namespace tvm
#endif // TVM_IR_DIAGNOSTIC_H_
47 changes: 22 additions & 25 deletions include/tvm/parser/source_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,33 @@ namespace parser {
* Could represent the source from an ML framework or a source
* representing a tvm::IRModule.
*/
struct Source {
/*! \brief The source name. */
class Source;

class SourceNode : public Object {
public:
/*! \brief The source name. */
SourceName source_name;

/*! \brief The raw source. */
std::string source;

/*! \brief A mapping of line breaks into the raw source. */
std::vector<std::pair<int, int>> line_map;

/*! \brief An empty source. */
Source() : source_name(), source(), line_map() {}

/*! \brief Construct a source from a string. */
TVM_DLL explicit Source(const SourceName& src_name, const std::string& source);

TVM_DLL Source(const Source& source)
: source_name(source.source_name), source(source.source), line_map(source.line_map) {}

/*! \brief Generate an error message at a specific line and column with the
* annotated message.
*
* The error is written directly to the `out` std::ostream.
*
* \param out The output ostream.
* \param span The span to report the error at.
* \param msg The message to attach.
*
*/
// TODO(@jroesch): replace the ostream with an interface for rendering errors.
TVM_DLL void ReportAt(std::ostream& out, const Span& span, const std::string& msg) const;
// override attr visitor
void VisitAttrs(AttrVisitor* v) {
v->Visit("source_name", &source_name);
}

static constexpr const char* _type_key = "Source";
TVM_DECLARE_FINAL_OBJECT_INFO(SourceNode, Object);
};

class Source : public ObjectRef {
public:
TVM_DLL Source(SourceName src_name, std::string source);

TVM_DEFINE_OBJECT_REF_METHODS(Source, ObjectRef, SourceNode);
};

/*!
Expand All @@ -82,7 +79,7 @@ class SourceMap;
class SourceMapNode : public Object {
public:
/*! \brief The source mapping. */
Map<SourceName, tvm::String> source_map;
Map<SourceName, Source> source_map;

// override attr visitor
void VisitAttrs(AttrVisitor* v) { v->Visit("source_map", &source_map); }
Expand All @@ -97,7 +94,7 @@ class SourceMapNode : public Object {

class SourceMap : public ObjectRef {
public:
TVM_DLL SourceMap(Map<SourceName, tvm::String> source_map);
TVM_DLL SourceMap(Map<SourceName, Source> source_map);

TVM_DLL static SourceMap Global();

Expand Down
2 changes: 1 addition & 1 deletion include/tvm/runtime/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ struct ObjectPtrEqual {
* \param ParentType The name of the ParentType
*/
#define TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType) \
static_assert(!ParentType::_type_final, "ParentObj maked as final"); \
static_assert(!ParentType::_type_final, "ParentObj marked as final"); \
static uint32_t RuntimeTypeIndex() { \
static_assert(TypeName::_type_child_slots == 0 || ParentType::_type_child_slots == 0 || \
TypeName::_type_child_slots < ParentType::_type_child_slots, \
Expand Down
6 changes: 6 additions & 0 deletions rust/tvm-rt/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct Array<T: IsObjectRef> {
external! {
#[name("node.ArrayGetItem")]
fn array_get_item(array: ObjectRef, index: isize) -> ObjectRef;
#[name("node.ArraySize")]
fn array_size(array: ObjectRef) -> i64;
}

impl<T: IsObjectRef> Array<T> {
Expand Down Expand Up @@ -76,4 +78,8 @@ impl<T: IsObjectRef> Array<T> {
let oref: ObjectRef = array_get_item(self.object.clone(), index)?;
oref.downcast()
}

pub fn len(&self) -> Result<i64> {
array_size(self.object.clone())
}
}
67 changes: 61 additions & 6 deletions src/ir/diagnostic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
* \file src/ir/transform.cc
* \brief Infrastructure for transformation passes.
*/
#include <tvm/parser/source_map.h>
#include <tvm/ir/diagnostic.h>

namespace tvm {

using tvm::parser::Source;

Diagnostic::Diagnostic(DiagnosticLevel level, Span span, const std::string& message) {
auto n = make_object<DiagnosticNode>();
n->level = level;
Expand Down Expand Up @@ -70,17 +73,69 @@ void DiagnosticContext::EmitFatal(const Diagnostic& diagnostic) {
Render(std::cout);
}

void DiagnosticContext::Render(const DiagnosticRenderer& renderer) {
renderer->Render();
}

/*! \brief Generate an error message at a specific line and column with the
* annotated message.
*
* The error is written directly to the `out` std::ostream.
*
* \param out The output ostream.
* \param line The line at which to report a diagnostic.
* \param line The column at which to report a diagnostic.
* \param msg The message to attach.
*/
void ReportAt(const DiagnosticContext& context, std::ostream& out, const Span& span, const std::string& msg) {
auto it = context->source_map->source_map.find(span->source_name);
CHECK(it != context->source_map->source_map.end());
auto source = (*it).second;

DLOG(INFO) << "ReportAt"
<< "span = " << span << "msg = " << msg;
int line = span->line;
int column = span->column;

CHECK(line - 1 <= static_cast<int64_t>(source->line_map.size()))
<< "requested line: " << (line - 1) << "line_map size: " << source->line_map.size()
<< "source: " << source->source;

// Adjust for zero indexing, now have (line_start, line_length);
auto range = source->line_map.at(line - 1);
int line_start = range.first;
int line_length = range.second;
out << "file:" << line << ":" << column << ": parse error: " << msg << std::endl;
out << " " << source->source.substr(line_start, line_length) << std::endl;
out << " ";

std::stringstream marker;
for (int i = 1; i <= line_length; i++) {
if (i == column) {
marker << "^";
} else if ((column - i) < 3) {
marker << "~";
} else if ((i - column) < 3) {
marker << "~";
} else {
marker << " ";
}
}
out << marker.str();
out << std::endl;
}

// TODO(@jroesch): eventually modularize the rendering interface to provide control of how to
// format errors.
void DiagnosticContext::Render(std::ostream& ostream) {
// for (auto diagnostic : diagnostics) {
// source.ReportAt(ostream, diagnostic.span, diagnostic.message);
// }
void TerminalRenderer::Render(const DiagnosticContext& ctx) override {
for (auto diagnostic : this->ctx->diagnostics) {
ReportAt(this->ctx, ostream, diagnostic->span, diagnostic->message);
}

if ((*this)->diagnostics.size()) {
if (this->ctx->diagnostics.size()) {
LOG(FATAL) << "DiagnosticError: one or more error diagnostics were "
<< "emitted, please check diagnostic render for output.";
}
}

} // namespace tvm
}
7 changes: 6 additions & 1 deletion src/parser/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ class Parser {
return Bracket(TokenType::kLCurly, TokenType::kRCurly, parser);
}

/*! \brief Parse a meta reference this is of the form `meta[type_key][node_index]`. */
// meta[relay.Constant][0]
// meta[relay.Constant][1]
ObjectRef ParseMetaRef() {
auto meta_ref = Match(TokenType::kMetaReference);
Call ref = Downcast<Call>(meta_ref->data);
Expand Down Expand Up @@ -645,7 +648,9 @@ class Parser {
} else if (required) {
this->diag_ctx->Emit(Diagnostic::Error(Peek()->span)
<< "expected text format semantic version, found a "
<< PrettyPrint(Peek())
<< PrettyPrint(Peek()));

this->diag_ctx->Emit(Diagnostic::Help(Peek()->span)
<< "you can annotate it as #[version = \"0.0.5\"]");
}
return SemVer(0, 0, 5);
Expand Down
Loading

0 comments on commit df57f66

Please sign in to comment.