blob: 721a30affa3ffc2bf800266eda87a735af560402 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*!
* \file source_map.cc
* \brief The implementation of the source map data structure.
*/
#include <tvm/ir/source_map.h>
#include <tvm/ir/transform.h>
#include <tvm/runtime/registry.h>
#include <algorithm>
namespace tvm {
TVM_REGISTER_PASS_CONFIG_OPTION("relay.frontend.fill_span", Bool);
ObjectPtr<Object> GetSourceNameNode(const String& name) {
// always return pointer as the reference can change as map re-allocate.
// or use another level of indirection by creating a unique_ptr
static std::unordered_map<String, ObjectPtr<SourceNameNode>> source_map;
auto sn = source_map.find(name);
if (sn == source_map.end()) {
ObjectPtr<SourceNameNode> n = make_object<SourceNameNode>();
source_map[name] = n;
n->name = std::move(name);
return n;
} else {
return sn->second;
}
}
ObjectPtr<Object> GetSourceNameNodeByStr(const std::string& name) {
return GetSourceNameNode(name);
}
SourceName SourceName::Get(const String& name) { return SourceName(GetSourceNameNode(name)); }
TVM_REGISTER_GLOBAL("ir.SourceName").set_body_typed(SourceName::Get);
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<SourceNameNode>([](const ObjectRef& ref, ReprPrinter* p) {
auto* node = static_cast<const SourceNameNode*>(ref.get());
p->stream << "SourceName(" << node->name << ", " << node << ")";
});
TVM_REGISTER_NODE_TYPE(SourceNameNode)
.set_creator(GetSourceNameNodeByStr)
.set_repr_bytes([](const Object* n) -> std::string {
return static_cast<const SourceNameNode*>(n)->name;
});
Span::Span(SourceName source_name, int line, int end_line, int column, int end_column) {
auto n = make_object<SpanNode>();
n->source_name = std::move(source_name);
n->line = line;
n->end_line = end_line;
n->column = column;
n->end_column = end_column;
data_ = std::move(n);
}
Span Span::Merge(const Span& other) const {
ICHECK(this->defined() && other.defined()) << "Span::Merge: both spans must be defined";
ICHECK((*this)->source_name == other->source_name);
return Span((*this)->source_name, std::min((*this)->line, other->line),
std::max((*this)->end_line, other->end_line),
std::min((*this)->column, other->column),
std::max((*this)->end_column, other->end_column));
}
TVM_REGISTER_NODE_TYPE(SpanNode);
SequentialSpan::SequentialSpan(tvm::Array<Span> spans) {
auto n = make_object<SequentialSpanNode>();
tvm::Array<Span> tmp_spans;
for (const Span& s : spans) {
if (const SequentialSpanNode* seq_s = s.as<SequentialSpanNode>()) {
tmp_spans.insert(tmp_spans.end(), seq_s->spans.begin(), seq_s->spans.end());
} else {
tmp_spans.push_back(s);
}
}
n->spans = std::move(tmp_spans);
n->line = 0;
n->end_line = 0;
n->column = 0;
n->end_column = 0;
data_ = std::move(n);
}
SequentialSpan::SequentialSpan(std::initializer_list<Span> init) {
auto n = make_object<SequentialSpanNode>();
tvm::Array<Span> spans = tvm::Array<Span>(init);
tvm::Array<Span> tmp_spans;
for (const Span& s : spans) {
if (const SequentialSpanNode* seq_s = s.as<SequentialSpanNode>()) {
tmp_spans.insert(tmp_spans.end(), seq_s->spans.begin(), seq_s->spans.end());
} else {
tmp_spans.push_back(s);
}
}
n->spans = std::move(tmp_spans);
n->line = 0;
n->end_line = 0;
n->column = 0;
n->end_column = 0;
data_ = std::move(n);
}
TVM_REGISTER_NODE_TYPE(SequentialSpanNode);
TVM_REGISTER_GLOBAL("ir.Span").set_body_typed([](SourceName source_name, int line, int end_line,
int column, int end_column) {
return Span(source_name, line, end_line, column, end_column);
});
TVM_REGISTER_GLOBAL("ir.SequentialSpan").set_body_typed([](tvm::Array<Span> spans) {
return SequentialSpan(spans);
});
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<SpanNode>([](const ObjectRef& ref, ReprPrinter* p) {
auto* node = static_cast<const SpanNode*>(ref.get());
p->stream << "Span(" << node->source_name << ", " << node->line << ", " << node->end_line
<< ", " << node->column << ", " << node->end_column << ")";
});
TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
.set_dispatch<SequentialSpanNode>([](const ObjectRef& ref, ReprPrinter* p) {
auto* node = static_cast<const SequentialSpanNode*>(ref.get());
p->stream << "SequentailSpan([ ";
int index = 0;
const int last = node->spans.size() - 1;
while (index < last) {
p->stream << node->spans[index++] << ", ";
}
p->stream << node->spans[last] << " ])";
});
TVM_REGISTER_NODE_TYPE(SourceNode);
/*! \brief Construct a source from a string. */
Source::Source(SourceName src_name, std::string source) {
auto n = make_object<SourceNode>();
n->source_name = std::move(src_name);
n->source = std::move(source);
int index = 0;
int length = 0;
n->line_map.push_back({index, length});
// NB(@jroesch):
std::string source_str = n->source;
for (auto c : source_str) {
if (c == '\n') {
// Record the length of the line.
n->line_map.back().second = length;
// Bump past the newline.
index += 1;
// Record the start of the next line, and put placeholder for length.
n->line_map.push_back({index, 0});
// Reset length to zero.
length = 0;
} else {
length += 1;
index += 1;
}
}
n->line_map.back().second = length;
data_ = n;
}
tvm::String Source::GetLine(int line) {
VLOG(1) << "Source::GetLine: line=" << line;
ICHECK(line - 1 < static_cast<int64_t>((*this)->line_map.size()))
<< "requested line: " << line << "at index: " << (line - 1)
<< "line_map size: " << (*this)->line_map.size() << "source: " << (*this)->source;
// Adjust for zero indexing, now have (line_start, line_length);
auto range = (*this)->line_map.at(line - 1);
int line_start = range.first;
int line_length = range.second;
VLOG(1) << "Source::GetLine: line_start=" << line_start << " line_length=" << line_length;
// TODO(@jroesch): expose substring on tvm::String.
auto line_text = std::string((*this)->source).substr(line_start, line_length);
VLOG(1) << "Source::GetLine: line_text=" << line_text;
return line_text;
}
TVM_REGISTER_NODE_TYPE(SourceMapNode);
SourceMap::SourceMap(Map<SourceName, Source> source_map) {
auto n = make_object<SourceMapNode>();
n->source_map = std::move(source_map);
data_ = std::move(n);
}
void SourceMap::Add(const Source& source) { (*this)->source_map.Set(source->source_name, source); }
TVM_REGISTER_GLOBAL("SourceMapAdd").set_body_typed([](SourceMap map, String name, String content) {
auto src_name = SourceName::Get(name);
Source source(src_name, content);
map.Add(source);
return src_name;
});
} // namespace tvm