2018-12-29 04:02:08 +08:00
|
|
|
//===- Operator.cpp - Operator class --------------------------------------===//
|
|
|
|
//
|
|
|
|
// Copyright 2019 The MLIR Authors.
|
|
|
|
//
|
|
|
|
// Licensed 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.
|
|
|
|
// =============================================================================
|
|
|
|
//
|
2019-01-08 02:09:34 +08:00
|
|
|
// Operator wrapper to simplify using TableGen Record defining a MLIR Op.
|
2018-12-29 04:02:08 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "mlir/TableGen/Operator.h"
|
2019-01-06 00:11:29 +08:00
|
|
|
#include "mlir/TableGen/Predicate.h"
|
2019-01-09 09:19:22 +08:00
|
|
|
#include "mlir/TableGen/Type.h"
|
2018-12-29 04:02:08 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
|
|
|
|
using namespace mlir;
|
2019-01-09 09:19:37 +08:00
|
|
|
|
2018-12-29 04:02:08 +08:00
|
|
|
using llvm::DagInit;
|
|
|
|
using llvm::DefInit;
|
|
|
|
using llvm::Record;
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
tblgen::Operator::Operator(const llvm::Record &def) : def(def) {
|
2018-12-29 04:02:08 +08:00
|
|
|
SplitString(def.getName(), splittedDefName, "_");
|
|
|
|
populateOperandsAndAttributes();
|
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
const SmallVectorImpl<StringRef> &tblgen::Operator::getSplitDefName() const {
|
2018-12-29 04:02:08 +08:00
|
|
|
return splittedDefName;
|
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
StringRef tblgen::Operator::getOperationName() const {
|
2018-12-29 04:02:08 +08:00
|
|
|
return def.getValueAsString("opName");
|
|
|
|
}
|
|
|
|
|
2019-02-06 04:02:53 +08:00
|
|
|
StringRef tblgen::Operator::getDialectName() const {
|
|
|
|
return getSplitDefName().front();
|
|
|
|
}
|
|
|
|
|
2019-01-30 01:27:04 +08:00
|
|
|
StringRef tblgen::Operator::getCppClassName() const {
|
2019-01-09 09:19:37 +08:00
|
|
|
return getSplitDefName().back();
|
|
|
|
}
|
2019-01-30 01:27:04 +08:00
|
|
|
std::string tblgen::Operator::getQualCppClassName() const {
|
2019-01-03 08:11:42 +08:00
|
|
|
return llvm::join(getSplitDefName(), "::");
|
|
|
|
}
|
2018-12-29 04:02:08 +08:00
|
|
|
|
2019-01-30 02:03:17 +08:00
|
|
|
int tblgen::Operator::getNumResults() const {
|
|
|
|
DagInit *results = def.getValueAsDag("results");
|
|
|
|
return results->getNumArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::Type tblgen::Operator::getResultType(int index) const {
|
|
|
|
DagInit *results = def.getValueAsDag("results");
|
|
|
|
return Type(cast<DefInit>(results->getArg(index)));
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::Operator::getResultName(int index) const {
|
|
|
|
DagInit *results = def.getValueAsDag("results");
|
|
|
|
return results->getArgNameStr(index);
|
|
|
|
}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
int tblgen::Operator::getNumNativeAttributes() const {
|
|
|
|
return derivedAttrStart - nativeAttrStart;
|
|
|
|
}
|
|
|
|
|
2019-02-06 04:02:53 +08:00
|
|
|
int tblgen::Operator::getNumDerivedAttributes() const {
|
|
|
|
return getNumAttributes() - getNumNativeAttributes();
|
|
|
|
}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
const tblgen::NamedAttribute &tblgen::Operator::getAttribute(int index) const {
|
|
|
|
return attributes[index];
|
|
|
|
}
|
|
|
|
|
2019-02-06 21:06:11 +08:00
|
|
|
bool tblgen::Operator::hasVariadicOperand() const {
|
|
|
|
return !operands.empty() && operands.back().type.isVariadic();
|
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
StringRef tblgen::Operator::getArgName(int index) const {
|
2018-12-29 04:02:08 +08:00
|
|
|
DagInit *argumentValues = def.getValueAsDag("arguments");
|
|
|
|
return argumentValues->getArgName(index)->getValue();
|
|
|
|
}
|
|
|
|
|
2019-02-15 02:54:50 +08:00
|
|
|
bool tblgen::Operator::hasTrait(StringRef trait) const {
|
|
|
|
auto traits = def.getValueAsListOfStrings("traits");
|
|
|
|
if (std::find(traits.begin(), traits.end(), trait) != traits.end())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-06 04:02:53 +08:00
|
|
|
auto tblgen::Operator::attribute_begin() const -> attribute_iterator {
|
2018-12-29 04:02:08 +08:00
|
|
|
return attributes.begin();
|
|
|
|
}
|
2019-02-06 04:02:53 +08:00
|
|
|
auto tblgen::Operator::attribute_end() const -> attribute_iterator {
|
2018-12-29 04:02:08 +08:00
|
|
|
return attributes.end();
|
|
|
|
}
|
2019-02-06 04:02:53 +08:00
|
|
|
auto tblgen::Operator::getAttributes() const
|
2019-01-09 09:19:37 +08:00
|
|
|
-> llvm::iterator_range<attribute_iterator> {
|
2018-12-29 04:02:08 +08:00
|
|
|
return {attribute_begin(), attribute_end()};
|
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
auto tblgen::Operator::operand_begin() -> operand_iterator {
|
|
|
|
return operands.begin();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::operand_end() -> operand_iterator {
|
|
|
|
return operands.end();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::getOperands() -> llvm::iterator_range<operand_iterator> {
|
2018-12-29 04:02:08 +08:00
|
|
|
return {operand_begin(), operand_end()};
|
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
auto tblgen::Operator::getArg(int index) -> Argument {
|
2019-01-08 02:09:34 +08:00
|
|
|
if (index < nativeAttrStart)
|
2018-12-29 04:02:08 +08:00
|
|
|
return {&operands[index]};
|
2019-01-08 02:09:34 +08:00
|
|
|
return {&attributes[index - nativeAttrStart]};
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
|
2019-01-09 09:19:37 +08:00
|
|
|
void tblgen::Operator::populateOperandsAndAttributes() {
|
2018-12-29 04:02:08 +08:00
|
|
|
auto &recordKeeper = def.getRecords();
|
|
|
|
auto attrClass = recordKeeper.getClass("Attr");
|
|
|
|
auto derivedAttrClass = recordKeeper.getClass("DerivedAttr");
|
|
|
|
derivedAttrStart = -1;
|
|
|
|
|
2019-01-08 02:09:34 +08:00
|
|
|
// The argument ordering is operands, native attributes, derived
|
2018-12-29 04:02:08 +08:00
|
|
|
// attributes.
|
|
|
|
DagInit *argumentValues = def.getValueAsDag("arguments");
|
|
|
|
unsigned i = 0;
|
|
|
|
// Handle operands.
|
|
|
|
for (unsigned e = argumentValues->getNumArgs(); i != e; ++i) {
|
|
|
|
auto arg = argumentValues->getArg(i);
|
2019-01-30 22:05:27 +08:00
|
|
|
auto givenName = argumentValues->getArgNameStr(i);
|
2018-12-29 04:02:08 +08:00
|
|
|
auto argDefInit = dyn_cast<DefInit>(arg);
|
|
|
|
if (!argDefInit)
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("undefined type for argument ") + Twine(i));
|
|
|
|
Record *argDef = argDefInit->getDef();
|
|
|
|
if (argDef->isSubClassOf(attrClass))
|
|
|
|
break;
|
2019-01-30 22:05:27 +08:00
|
|
|
operands.push_back(Operand{givenName, Type(argDefInit)});
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
|
2019-01-08 02:09:34 +08:00
|
|
|
// Handle native attributes.
|
|
|
|
nativeAttrStart = i;
|
2018-12-29 04:02:08 +08:00
|
|
|
for (unsigned e = argumentValues->getNumArgs(); i != e; ++i) {
|
|
|
|
auto arg = argumentValues->getArg(i);
|
2019-01-30 22:05:27 +08:00
|
|
|
auto givenName = argumentValues->getArgNameStr(i);
|
2018-12-29 04:02:08 +08:00
|
|
|
Record *argDef = cast<DefInit>(arg)->getDef();
|
|
|
|
if (!argDef->isSubClassOf(attrClass))
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("expected attribute as argument ") + Twine(i));
|
|
|
|
|
2019-01-30 22:05:27 +08:00
|
|
|
if (givenName.empty())
|
2018-12-29 04:02:08 +08:00
|
|
|
PrintFatalError(argDef->getLoc(), "attributes must be named");
|
|
|
|
bool isDerived = argDef->isSubClassOf(derivedAttrClass);
|
2019-01-04 07:53:54 +08:00
|
|
|
if (isDerived)
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
"derived attributes not allowed in argument list");
|
2019-01-10 05:50:20 +08:00
|
|
|
attributes.push_back({givenName, Attribute(argDef)});
|
2019-01-04 07:53:54 +08:00
|
|
|
}
|
2018-12-29 04:02:08 +08:00
|
|
|
|
2019-01-08 02:09:34 +08:00
|
|
|
// Handle derived attributes.
|
2019-01-04 07:53:54 +08:00
|
|
|
derivedAttrStart = i;
|
|
|
|
for (const auto &val : def.getValues()) {
|
|
|
|
if (auto *record = dyn_cast<llvm::RecordRecTy>(val.getType())) {
|
|
|
|
if (!record->isSubClassOf(attrClass))
|
|
|
|
continue;
|
|
|
|
if (!record->isSubClassOf(derivedAttrClass))
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
"unexpected Attr where only DerivedAttr is allowed");
|
|
|
|
|
|
|
|
if (record->getClasses().size() != 1) {
|
2018-12-29 04:02:08 +08:00
|
|
|
PrintFatalError(
|
|
|
|
def.getLoc(),
|
2019-01-04 07:53:54 +08:00
|
|
|
"unsupported attribute modelling, only single class expected");
|
|
|
|
}
|
2019-01-30 22:05:27 +08:00
|
|
|
attributes.push_back(
|
|
|
|
{cast<llvm::StringInit>(val.getNameInit())->getValue(),
|
|
|
|
Attribute(cast<DefInit>(val.getValue()))});
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
}
|
2019-02-06 21:06:11 +08:00
|
|
|
|
|
|
|
for (int i = 0, e = operands.size() - 1; i < e; ++i) {
|
|
|
|
if (operands[i].type.isVariadic())
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
"only the last operand allowed to be variadic");
|
|
|
|
}
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
2019-01-06 00:11:29 +08:00
|
|
|
|
2019-02-06 04:02:53 +08:00
|
|
|
ArrayRef<llvm::SMLoc> tblgen::Operator::getLoc() const { return def.getLoc(); }
|
|
|
|
|
Start doc generation pass.
Start doc generation pass that generates simple markdown output. The output is formatted simply[1] in markdown, but this allows seeing what info we have, where we can refine the op description (e.g., the inputs is probably redundant), what info is missing (e.g., the attributes could probably have a description).
The formatting of the description is still left up to whatever was in the op definition (which luckily, due to the uniformity in the .td file, turned out well but relying on the indentation there is fragile). The mechanism to autogenerate these post changes has not been added yet either. The output file could be run through a markdown formatter too to remove extra spaces.
[1]. This is not proposal for final style :) There could also be a discussion around single doc vs multiple (per dialect, per op), whether we want a TOC, whether operands/attributes should be headings or just formatted differently ...
PiperOrigin-RevId: 230354538
2019-01-23 01:31:04 +08:00
|
|
|
bool tblgen::Operator::hasDescription() const {
|
|
|
|
return def.getValue("description") != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::Operator::getDescription() const {
|
|
|
|
return def.getValueAsString("description");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tblgen::Operator::hasSummary() const {
|
|
|
|
return def.getValue("summary") != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::Operator::getSummary() const {
|
|
|
|
return def.getValueAsString("summary");
|
|
|
|
}
|