Skip to content

Commit

Permalink
[mlir] Generate C++ doc comments for interfaces
Browse files Browse the repository at this point in the history
When emitting the declarations for interface methods defined in ODS,
also emit their descriptions as C++ comments. This makes the
documentation accessible to C++ tooling such as IDEs that offers better
usability than reading it form the .td or the website.

Reviewed By: jpienaar

Differential Revision: https://reviews.llvm.org/D130478
  • Loading branch information
ftynse committed Aug 10, 2022
1 parent fa25025 commit 2e2ad53
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 11 deletions.
17 changes: 11 additions & 6 deletions mlir/include/mlir/Support/IndentedOstream.h
Expand Up @@ -59,8 +59,10 @@ class raw_indented_ostream : public raw_ostream {

/// Prints a string re-indented to the current indent. Re-indents by removing
/// the leading whitespace from the first non-empty line from every line of
/// the string, skipping over empty lines at the start.
raw_indented_ostream &printReindented(StringRef str);
/// the string, skipping over empty lines at the start. Prefixes each line
/// with extraPrefix after the indentation.
raw_indented_ostream &printReindented(StringRef str,
StringRef extraPrefix = "");

/// Increases the indent and returning this raw_indented_ostream.
raw_indented_ostream &indent() {
Expand Down Expand Up @@ -92,16 +94,19 @@ class raw_indented_ostream : public raw_ostream {
/// Constant indent added/removed.
static constexpr int indentSize = 2;

// Tracker for current indentation.
/// Tracker for current indentation.
int currentIndent = 0;

// The leading whitespace of the string being printed, if reindent is used.
/// The leading whitespace of the string being printed, if reindent is used.
int leadingWs = 0;

// Tracks whether at start of line and so indent is required or not.
/// The extra prefix to be printed, if reindent is used.
StringRef currentExtraPrefix;

/// Tracks whether at start of line and so indent is required or not.
bool atStartOfLine = true;

// The underlying raw_ostream.
/// The underlying raw_ostream.
raw_ostream &os;
};

Expand Down
12 changes: 8 additions & 4 deletions mlir/lib/Support/IndentedOstream.cpp
Expand Up @@ -16,7 +16,8 @@
using namespace mlir;

raw_indented_ostream &
mlir::raw_indented_ostream::printReindented(StringRef str) {
mlir::raw_indented_ostream::printReindented(StringRef str,
StringRef extraPrefix) {
StringRef output = str;
// Skip empty lines.
while (!output.empty()) {
Expand All @@ -39,7 +40,9 @@ mlir::raw_indented_ostream::printReindented(StringRef str) {
remaining = split.second;
}
// Print, skipping the empty lines.
std::swap(currentExtraPrefix, extraPrefix);
*this << output;
std::swap(currentExtraPrefix, extraPrefix);
leadingWs = 0;
return *this;
}
Expand All @@ -49,7 +52,7 @@ void mlir::raw_indented_ostream::write_impl(const char *ptr, size_t size) {
// Print out indented.
auto print = [this](StringRef str) {
if (atStartOfLine)
os.indent(currentIndent) << str.substr(leadingWs);
os.indent(currentIndent) << currentExtraPrefix << str.substr(leadingWs);
else
os << str.substr(leadingWs);
};
Expand All @@ -66,8 +69,9 @@ void mlir::raw_indented_ostream::write_impl(const char *ptr, size_t size) {

auto split =
std::make_pair(str.slice(0, idx), str.slice(idx + 1, StringRef::npos));
// Print empty new line without spaces if line only has spaces.
if (!split.first.ltrim().empty())
// Print empty new line without spaces if line only has spaces and no extra
// prefix is requested.
if (!split.first.ltrim().empty() || !currentExtraPrefix.empty())
print(split.first);
os << '\n';
atStartOfLine = true;
Expand Down
1 change: 1 addition & 0 deletions mlir/test/mlir-tblgen/op-interface.td
Expand Up @@ -73,6 +73,7 @@ def DeclareMethodsWithDefaultOp : Op<TestDialect, "declare_methods_op",
// DECL-LABEL: TestOpInterfaceInterfaceTraits
// DECL: class TestOpInterface : public ::mlir::OpInterface<TestOpInterface, detail::TestOpInterfaceInterfaceTraits>

// DECL: /// some function comment
// DECL: int foo(int input);

// DECL: template<typename ConcreteOp>
Expand Down
7 changes: 6 additions & 1 deletion mlir/tools/mlir-tblgen/DocGenUtilities.h
Expand Up @@ -14,9 +14,10 @@
#ifndef MLIR_TOOLS_MLIRTBLGEN_DOCGENUTILITIES_H_
#define MLIR_TOOLS_MLIRTBLGEN_DOCGENUTILITIES_H_

#include "llvm/ADT/StringRef.h"

namespace llvm {
class raw_ostream;
class StringRef;
} // namespace llvm

namespace mlir {
Expand All @@ -30,6 +31,10 @@ namespace tblgen {
// nested.
void emitDescription(llvm::StringRef description, llvm::raw_ostream &os);

// Emit the description as a C++ comment while realigning it.
void emitDescriptionComment(llvm::StringRef description, llvm::raw_ostream &os,
llvm::StringRef prefix = "");

} // namespace tblgen
} // namespace mlir

Expand Down
11 changes: 11 additions & 0 deletions mlir/tools/mlir-tblgen/OpDocGen.cpp
Expand Up @@ -48,6 +48,17 @@ void mlir::tblgen::emitDescription(StringRef description, raw_ostream &os) {
ros.printReindented(description.rtrim(" \t"));
}

void mlir::tblgen::emitDescriptionComment(StringRef description,
raw_ostream &os, StringRef prefix) {
if (description.empty())
return;
raw_indented_ostream ros(os);
StringRef trimmed = description.rtrim(" \t");
ros.printReindented(trimmed, (Twine(prefix) + "/// ").str());
if (!trimmed.endswith("\n"))
ros << "\n";
}

// Emits `str` with trailing newline if not empty.
static void emitIfNotEmpty(StringRef str, raw_ostream &os) {
if (!str.empty()) {
Expand Down
9 changes: 9 additions & 0 deletions mlir/tools/mlir-tblgen/OpInterfacesGen.cpp
Expand Up @@ -158,6 +158,12 @@ struct TypeInterfaceGenerator : public InterfaceGenerator {
// GEN: Interface definitions
//===----------------------------------------------------------------------===//

static void emitInterfaceMethodDoc(const InterfaceMethod &method,
raw_ostream &os, StringRef prefix = "") {
if (Optional<StringRef> description = method.getDescription())
tblgen::emitDescriptionComment(*description, os, prefix);
}

static void emitInterfaceDef(const Interface &interface, StringRef valueType,
raw_ostream &os) {
StringRef interfaceName = interface.getName();
Expand All @@ -167,6 +173,7 @@ static void emitInterfaceDef(const Interface &interface, StringRef valueType,
// Insert the method definitions.
bool isOpInterface = isa<OpInterface>(interface);
for (auto &method : interface.getMethods()) {
emitInterfaceMethodDoc(method, os);
emitCPPType(method.getReturnType(), os);
if (!cppNamespace.empty())
os << cppNamespace << "::";
Expand Down Expand Up @@ -401,6 +408,7 @@ void InterfaceGenerator::emitTraitDecl(const Interface &interface,
if (!defaultImpl)
continue;

emitInterfaceMethodDoc(method, os, " ");
os << " " << (method.isStatic() ? "static " : "");
emitCPPType(method.getReturnType(), os);
emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
Expand Down Expand Up @@ -470,6 +478,7 @@ void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
// Insert the method declarations.
bool isOpInterface = isa<OpInterface>(interface);
for (auto &method : interface.getMethods()) {
emitInterfaceMethodDoc(method, os, " ");
emitCPPType(method.getReturnType(), os << " ");
emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
/*addConst=*/!isOpInterface);
Expand Down

0 comments on commit 2e2ad53

Please sign in to comment.