2018-12-29 04:02:08 +08:00
|
|
|
//===- Operator.cpp - Operator class --------------------------------------===//
|
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-24 01:35:36 +08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-12-29 04:02:08 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2018-12-29 04:02:08 +08:00
|
|
|
//
|
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-02-21 02:50:26 +08:00
|
|
|
#include "mlir/TableGen/OpTrait.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"
|
2019-12-20 08:43:35 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2020-04-15 05:53:50 +08:00
|
|
|
#include "llvm/ADT/TypeSwitch.h"
|
2020-03-01 09:11:12 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2018-12-29 04:02:08 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
|
2019-11-15 03:02:52 +08:00
|
|
|
#define DEBUG_TYPE "mlir-tblgen-operator"
|
|
|
|
|
2018-12-29 04:02:08 +08:00
|
|
|
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-05-21 00:33:10 +08:00
|
|
|
tblgen::Operator::Operator(const llvm::Record &def)
|
|
|
|
: dialect(def.getValueAsDef("opDialect")), def(def) {
|
|
|
|
// The first `_` in the op's TableGen def name is treated as separating the
|
|
|
|
// dialect prefix and the op class name. The dialect prefix will be ignored if
|
|
|
|
// not empty. Otherwise, if def name starts with a `_`, the `_` is considered
|
|
|
|
// as part of the class name.
|
|
|
|
StringRef prefix;
|
|
|
|
std::tie(prefix, cppClassName) = def.getName().split('_');
|
|
|
|
if (prefix.empty()) {
|
|
|
|
// Class name with a leading underscore and without dialect prefix
|
2019-04-16 00:13:22 +08:00
|
|
|
cppClassName = def.getName();
|
|
|
|
} else if (cppClassName.empty()) {
|
2019-05-21 00:33:10 +08:00
|
|
|
// Class name without dialect prefix
|
|
|
|
cppClassName = prefix;
|
2019-04-16 00:13:22 +08:00
|
|
|
}
|
2018-12-29 04:02:08 +08:00
|
|
|
|
2019-04-16 00:13:22 +08:00
|
|
|
populateOpStructure();
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
|
2019-04-30 00:24:09 +08:00
|
|
|
std::string tblgen::Operator::getOperationName() const {
|
2019-05-21 00:33:10 +08:00
|
|
|
auto prefix = dialect.getName();
|
|
|
|
auto opName = def.getValueAsString("opName");
|
2019-04-30 00:24:09 +08:00
|
|
|
if (prefix.empty())
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(opName);
|
|
|
|
return std::string(llvm::formatv("{0}.{1}", prefix, opName));
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
|
2019-05-21 00:33:10 +08:00
|
|
|
StringRef tblgen::Operator::getDialectName() const { return dialect.getName(); }
|
2019-04-16 00:13:22 +08:00
|
|
|
|
2019-05-21 00:33:10 +08:00
|
|
|
StringRef tblgen::Operator::getCppClassName() const { return cppClassName; }
|
|
|
|
|
2019-01-30 01:27:04 +08:00
|
|
|
std::string tblgen::Operator::getQualCppClassName() const {
|
2019-05-21 00:33:10 +08:00
|
|
|
auto prefix = dialect.getCppNamespace();
|
|
|
|
if (prefix.empty())
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(cppClassName);
|
|
|
|
return std::string(llvm::formatv("{0}::{1}", prefix, cppClassName));
|
2019-01-03 08:11:42 +08:00
|
|
|
}
|
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();
|
|
|
|
}
|
|
|
|
|
2019-04-30 14:12:40 +08:00
|
|
|
StringRef tblgen::Operator::getExtraClassDeclaration() const {
|
|
|
|
constexpr auto attr = "extraClassDeclaration";
|
|
|
|
if (def.isValueUnset(attr))
|
|
|
|
return {};
|
|
|
|
return def.getValueAsString(attr);
|
|
|
|
}
|
|
|
|
|
2019-06-03 23:03:20 +08:00
|
|
|
const llvm::Record &tblgen::Operator::getDef() const { return def; }
|
|
|
|
|
2019-07-05 17:27:39 +08:00
|
|
|
bool tblgen::Operator::skipDefaultBuilders() const {
|
|
|
|
return def.getValueAsBit("skipDefaultBuilders");
|
|
|
|
}
|
|
|
|
|
2019-06-04 20:03:42 +08:00
|
|
|
auto tblgen::Operator::result_begin() -> value_iterator {
|
|
|
|
return results.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto tblgen::Operator::result_end() -> value_iterator { return results.end(); }
|
|
|
|
|
2019-06-09 22:00:09 +08:00
|
|
|
auto tblgen::Operator::getResults() -> value_range {
|
2019-06-04 20:03:42 +08:00
|
|
|
return {result_begin(), result_end()};
|
|
|
|
}
|
|
|
|
|
2019-03-18 22:54:20 +08:00
|
|
|
tblgen::TypeConstraint
|
|
|
|
tblgen::Operator::getResultTypeConstraint(int index) const {
|
2019-02-21 02:50:26 +08:00
|
|
|
DagInit *results = def.getValueAsDag("results");
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
return TypeConstraint(cast<DefInit>(results->getArg(index)));
|
2019-01-30 02:03:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::Operator::getResultName(int index) const {
|
2019-02-21 02:50:26 +08:00
|
|
|
DagInit *results = def.getValueAsDag("results");
|
|
|
|
return results->getArgNameStr(index);
|
2019-02-19 23:15:59 +08:00
|
|
|
}
|
|
|
|
|
2020-03-07 05:55:36 +08:00
|
|
|
auto tblgen::Operator::getResultDecorators(int index) const
|
|
|
|
-> var_decorator_range {
|
|
|
|
Record *result =
|
|
|
|
cast<DefInit>(def.getValueAsDag("results")->getArg(index))->getDef();
|
|
|
|
if (!result->isSubClassOf("OpVariable"))
|
|
|
|
return var_decorator_range(nullptr, nullptr);
|
|
|
|
return *result->getValueAsListInit("decorators");
|
|
|
|
}
|
|
|
|
|
2020-04-11 05:11:45 +08:00
|
|
|
unsigned tblgen::Operator::getNumVariableLengthResults() const {
|
|
|
|
return llvm::count_if(results, [](const NamedTypeConstraint &c) {
|
|
|
|
return c.constraint.isVariableLength();
|
|
|
|
});
|
2019-01-30 02:03:17 +08:00
|
|
|
}
|
|
|
|
|
2020-04-11 05:11:45 +08:00
|
|
|
unsigned tblgen::Operator::getNumVariableLengthOperands() const {
|
|
|
|
return llvm::count_if(operands, [](const NamedTypeConstraint &c) {
|
|
|
|
return c.constraint.isVariableLength();
|
|
|
|
});
|
2019-02-06 21:06:11 +08:00
|
|
|
}
|
|
|
|
|
2019-10-22 11:47:49 +08:00
|
|
|
tblgen::Operator::arg_iterator tblgen::Operator::arg_begin() const {
|
|
|
|
return arguments.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::Operator::arg_iterator tblgen::Operator::arg_end() const {
|
|
|
|
return arguments.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::Operator::arg_range tblgen::Operator::getArgs() const {
|
|
|
|
return {arg_begin(), arg_end()};
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-03-07 05:55:36 +08:00
|
|
|
auto tblgen::Operator::getArgDecorators(int index) const
|
|
|
|
-> var_decorator_range {
|
|
|
|
Record *arg =
|
|
|
|
cast<DefInit>(def.getValueAsDag("arguments")->getArg(index))->getDef();
|
|
|
|
if (!arg->isSubClassOf("OpVariable"))
|
|
|
|
return var_decorator_range(nullptr, nullptr);
|
|
|
|
return *arg->getValueAsListInit("decorators");
|
|
|
|
}
|
|
|
|
|
2019-11-26 09:26:16 +08:00
|
|
|
const tblgen::OpTrait *tblgen::Operator::getTrait(StringRef trait) const {
|
|
|
|
for (const auto &t : traits) {
|
2019-03-27 06:31:15 +08:00
|
|
|
if (auto opTrait = dyn_cast<tblgen::NativeOpTrait>(&t)) {
|
2019-02-21 02:50:26 +08:00
|
|
|
if (opTrait->getTrait() == trait)
|
2019-11-26 09:26:16 +08:00
|
|
|
return opTrait;
|
2019-03-27 06:31:15 +08:00
|
|
|
} else if (auto opTrait = dyn_cast<tblgen::InternalOpTrait>(&t)) {
|
|
|
|
if (opTrait->getTrait() == trait)
|
2019-11-26 09:26:16 +08:00
|
|
|
return opTrait;
|
2019-11-22 06:34:03 +08:00
|
|
|
} else if (auto opTrait = dyn_cast<tblgen::InterfaceOpTrait>(&t)) {
|
|
|
|
if (opTrait->getTrait() == trait)
|
2019-11-26 09:26:16 +08:00
|
|
|
return opTrait;
|
2019-03-27 06:31:15 +08:00
|
|
|
}
|
2019-02-21 02:50:26 +08:00
|
|
|
}
|
2019-11-26 09:26:16 +08:00
|
|
|
return nullptr;
|
2019-02-15 02:54:50 +08:00
|
|
|
}
|
|
|
|
|
2020-04-05 16:03:24 +08:00
|
|
|
auto tblgen::Operator::region_begin() const -> const_region_iterator {
|
|
|
|
return regions.begin();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::region_end() const -> const_region_iterator {
|
|
|
|
return regions.end();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::getRegions() const
|
|
|
|
-> llvm::iterator_range<const_region_iterator> {
|
|
|
|
return {region_begin(), region_end()};
|
|
|
|
}
|
|
|
|
|
2019-05-31 07:50:16 +08:00
|
|
|
unsigned tblgen::Operator::getNumRegions() const { return regions.size(); }
|
|
|
|
|
|
|
|
const tblgen::NamedRegion &tblgen::Operator::getRegion(unsigned index) const {
|
|
|
|
return regions[index];
|
|
|
|
}
|
2019-05-28 23:03:46 +08:00
|
|
|
|
2020-04-05 16:03:24 +08:00
|
|
|
unsigned tblgen::Operator::getNumVariadicRegions() const {
|
|
|
|
return llvm::count_if(regions,
|
|
|
|
[](const NamedRegion &c) { return c.isVariadic(); });
|
|
|
|
}
|
|
|
|
|
2020-02-22 05:19:50 +08:00
|
|
|
auto tblgen::Operator::successor_begin() const -> const_successor_iterator {
|
|
|
|
return successors.begin();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::successor_end() const -> const_successor_iterator {
|
|
|
|
return successors.end();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::getSuccessors() const
|
|
|
|
-> llvm::iterator_range<const_successor_iterator> {
|
|
|
|
return {successor_begin(), successor_end()};
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned tblgen::Operator::getNumSuccessors() const {
|
|
|
|
return successors.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
const tblgen::NamedSuccessor &
|
|
|
|
tblgen::Operator::getSuccessor(unsigned index) const {
|
|
|
|
return successors[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned tblgen::Operator::getNumVariadicSuccessors() const {
|
|
|
|
return llvm::count_if(successors,
|
|
|
|
[](const NamedSuccessor &c) { return c.isVariadic(); });
|
|
|
|
}
|
|
|
|
|
2019-02-21 02:50:26 +08:00
|
|
|
auto tblgen::Operator::trait_begin() const -> const_trait_iterator {
|
|
|
|
return traits.begin();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::trait_end() const -> const_trait_iterator {
|
|
|
|
return traits.end();
|
|
|
|
}
|
|
|
|
auto tblgen::Operator::getTraits() const
|
|
|
|
-> llvm::iterator_range<const_trait_iterator> {
|
|
|
|
return {trait_begin(), trait_end()};
|
|
|
|
}
|
|
|
|
|
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-06-04 20:03:42 +08:00
|
|
|
auto tblgen::Operator::operand_begin() -> value_iterator {
|
2019-01-09 09:19:37 +08:00
|
|
|
return operands.begin();
|
|
|
|
}
|
2019-06-04 20:03:42 +08:00
|
|
|
auto tblgen::Operator::operand_end() -> value_iterator {
|
2019-01-09 09:19:37 +08:00
|
|
|
return operands.end();
|
|
|
|
}
|
2019-06-09 22:00:09 +08:00
|
|
|
auto tblgen::Operator::getOperands() -> value_range {
|
2018-12-29 04:02:08 +08:00
|
|
|
return {operand_begin(), operand_end()};
|
|
|
|
}
|
|
|
|
|
2019-07-18 09:41:28 +08:00
|
|
|
auto tblgen::Operator::getArg(int index) const -> Argument {
|
2019-03-06 17:23:41 +08:00
|
|
|
return arguments[index];
|
2018-12-29 04:02:08 +08:00
|
|
|
}
|
|
|
|
|
2019-02-19 23:15:59 +08:00
|
|
|
void tblgen::Operator::populateOpStructure() {
|
2018-12-29 04:02:08 +08:00
|
|
|
auto &recordKeeper = def.getRecords();
|
2019-03-06 17:23:41 +08:00
|
|
|
auto typeConstraintClass = recordKeeper.getClass("TypeConstraint");
|
2018-12-29 04:02:08 +08:00
|
|
|
auto attrClass = recordKeeper.getClass("Attr");
|
|
|
|
auto derivedAttrClass = recordKeeper.getClass("DerivedAttr");
|
2020-03-07 05:55:36 +08:00
|
|
|
auto opVarClass = recordKeeper.getClass("OpVariable");
|
2019-03-06 17:23:41 +08:00
|
|
|
numNativeAttributes = 0;
|
2018-12-29 04:02:08 +08:00
|
|
|
|
|
|
|
DagInit *argumentValues = def.getValueAsDag("arguments");
|
2019-11-15 03:02:52 +08:00
|
|
|
unsigned numArgs = argumentValues->getNumArgs();
|
|
|
|
|
2019-03-06 17:23:41 +08:00
|
|
|
// Handle operands and native attributes.
|
2019-11-15 03:02:52 +08:00
|
|
|
for (unsigned i = 0; i != numArgs; ++i) {
|
2018-12-29 04:02:08 +08:00
|
|
|
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(),
|
2019-02-19 23:15:59 +08:00
|
|
|
Twine("undefined type for argument #") + Twine(i));
|
2018-12-29 04:02:08 +08:00
|
|
|
Record *argDef = argDefInit->getDef();
|
2020-03-07 05:55:36 +08:00
|
|
|
if (argDef->isSubClassOf(opVarClass))
|
|
|
|
argDef = argDef->getValueAsDef("constraint");
|
2018-12-29 04:02:08 +08:00
|
|
|
|
2019-03-06 17:23:41 +08:00
|
|
|
if (argDef->isSubClassOf(typeConstraintClass)) {
|
2019-03-18 22:54:20 +08:00
|
|
|
operands.push_back(
|
2020-03-07 05:55:36 +08:00
|
|
|
NamedTypeConstraint{givenName, TypeConstraint(argDef)});
|
2019-03-06 17:23:41 +08:00
|
|
|
} else if (argDef->isSubClassOf(attrClass)) {
|
|
|
|
if (givenName.empty())
|
|
|
|
PrintFatalError(argDef->getLoc(), "attributes must be named");
|
|
|
|
if (argDef->isSubClassOf(derivedAttrClass))
|
|
|
|
PrintFatalError(argDef->getLoc(),
|
|
|
|
"derived attributes not allowed in argument list");
|
|
|
|
attributes.push_back({givenName, Attribute(argDef)});
|
|
|
|
++numNativeAttributes;
|
|
|
|
} else {
|
|
|
|
PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving "
|
|
|
|
"from TypeConstraint or Attr are allowed");
|
|
|
|
}
|
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
|
|
|
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
|
|
|
|
2019-11-15 03:02:52 +08:00
|
|
|
// Populate `arguments`. This must happen after we've finalized `operands` and
|
|
|
|
// `attributes` because we will put their elements' pointers in `arguments`.
|
|
|
|
// SmallVector may perform re-allocation under the hood when adding new
|
|
|
|
// elements.
|
|
|
|
int operandIndex = 0, attrIndex = 0;
|
|
|
|
for (unsigned i = 0; i != numArgs; ++i) {
|
|
|
|
Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
|
2020-03-07 05:55:36 +08:00
|
|
|
if (argDef->isSubClassOf(opVarClass))
|
|
|
|
argDef = argDef->getValueAsDef("constraint");
|
2019-11-15 03:02:52 +08:00
|
|
|
|
|
|
|
if (argDef->isSubClassOf(typeConstraintClass)) {
|
|
|
|
arguments.emplace_back(&operands[operandIndex++]);
|
|
|
|
} else {
|
|
|
|
assert(argDef->isSubClassOf(attrClass));
|
|
|
|
arguments.emplace_back(&attributes[attrIndex++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 23:15:59 +08:00
|
|
|
auto *resultsDag = def.getValueAsDag("results");
|
|
|
|
auto *outsOp = dyn_cast<DefInit>(resultsDag->getOperator());
|
|
|
|
if (!outsOp || outsOp->getDef()->getName() != "outs") {
|
|
|
|
PrintFatalError(def.getLoc(), "'results' must have 'outs' directive");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle results.
|
|
|
|
for (unsigned i = 0, e = resultsDag->getNumArgs(); i < e; ++i) {
|
|
|
|
auto name = resultsDag->getArgNameStr(i);
|
2020-03-07 05:55:36 +08:00
|
|
|
auto *resultInit = dyn_cast<DefInit>(resultsDag->getArg(i));
|
|
|
|
if (!resultInit) {
|
2019-02-19 23:15:59 +08:00
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("undefined type for result #") + Twine(i));
|
|
|
|
}
|
2020-03-07 05:55:36 +08:00
|
|
|
auto *resultDef = resultInit->getDef();
|
|
|
|
if (resultDef->isSubClassOf(opVarClass))
|
|
|
|
resultDef = resultDef->getValueAsDef("constraint");
|
[TableGen] Consolidate constraint related concepts
Previously we have multiple mechanisms to specify op definition and match constraints:
TypeConstraint, AttributeConstraint, Type, Attr, mAttr, mAttrAnyOf, mPat. These variants
are not added because there are so many distinct cases we need to model; essentially,
they are all carrying a predicate. It's just an artifact of implementation.
It's quite confusing for users to grasp these variants and choose among them. Instead,
as the OpBase TableGen file, we need to strike to provide an unified mechanism. Each
dialect has the flexibility to define its own aliases if wanted.
This CL removes mAttr, mAttrAnyOf, mPat. A new base class, Constraint, is added. Now
TypeConstraint and AttrConstraint derive from Constraint. Type and Attr further derive
from TypeConstraint and AttrConstraint, respectively.
Comments are revised and examples are added to make it clear how to use constraints.
PiperOrigin-RevId: 240125076
2019-03-25 21:09:26 +08:00
|
|
|
results.push_back({name, TypeConstraint(resultDef)});
|
2019-02-19 23:15:59 +08:00
|
|
|
}
|
|
|
|
|
2020-02-22 05:19:50 +08:00
|
|
|
// Handle successors
|
|
|
|
auto *successorsDag = def.getValueAsDag("successors");
|
|
|
|
auto *successorsOp = dyn_cast<DefInit>(successorsDag->getOperator());
|
|
|
|
if (!successorsOp || successorsOp->getDef()->getName() != "successor") {
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
"'successors' must have 'successor' directive");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = successorsDag->getNumArgs(); i < e; ++i) {
|
|
|
|
auto name = successorsDag->getArgNameStr(i);
|
|
|
|
auto *successorInit = dyn_cast<DefInit>(successorsDag->getArg(i));
|
|
|
|
if (!successorInit) {
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("undefined kind for successor #") + Twine(i));
|
|
|
|
}
|
|
|
|
Successor successor(successorInit->getDef());
|
|
|
|
|
|
|
|
// Only support variadic successors if it is the last one for now.
|
|
|
|
if (i != e - 1 && successor.isVariadic())
|
|
|
|
PrintFatalError(def.getLoc(), "only the last successor can be variadic");
|
|
|
|
successors.push_back({name, successor});
|
|
|
|
}
|
|
|
|
|
2019-12-20 08:43:35 +08:00
|
|
|
// Create list of traits, skipping over duplicates: appending to lists in
|
|
|
|
// tablegen is easy, making them unique less so, so dedupe here.
|
|
|
|
if (auto traitList = def.getValueAsListInit("traits")) {
|
|
|
|
// This is uniquing based on pointers of the trait.
|
|
|
|
SmallPtrSet<const llvm::Init *, 32> traitSet;
|
|
|
|
traits.reserve(traitSet.size());
|
|
|
|
for (auto traitInit : *traitList) {
|
|
|
|
// Keep traits in the same order while skipping over duplicates.
|
|
|
|
if (traitSet.insert(traitInit).second)
|
|
|
|
traits.push_back(OpTrait::create(traitInit));
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 23:03:46 +08:00
|
|
|
|
|
|
|
// Handle regions
|
2019-05-31 07:50:16 +08:00
|
|
|
auto *regionsDag = def.getValueAsDag("regions");
|
|
|
|
auto *regionsOp = dyn_cast<DefInit>(regionsDag->getOperator());
|
|
|
|
if (!regionsOp || regionsOp->getDef()->getName() != "region") {
|
|
|
|
PrintFatalError(def.getLoc(), "'regions' must have 'region' directive");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = regionsDag->getNumArgs(); i < e; ++i) {
|
|
|
|
auto name = regionsDag->getArgNameStr(i);
|
|
|
|
auto *regionInit = dyn_cast<DefInit>(regionsDag->getArg(i));
|
|
|
|
if (!regionInit) {
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("undefined kind for region #") + Twine(i));
|
|
|
|
}
|
2020-04-05 16:03:24 +08:00
|
|
|
Region region(regionInit->getDef());
|
|
|
|
if (region.isVariadic()) {
|
|
|
|
// Only support variadic regions if it is the last one for now.
|
|
|
|
if (i != e - 1)
|
|
|
|
PrintFatalError(def.getLoc(), "only the last region can be variadic");
|
|
|
|
if (name.empty())
|
|
|
|
PrintFatalError(def.getLoc(), "variadic regions must be named");
|
|
|
|
}
|
|
|
|
|
|
|
|
regions.push_back({name, region});
|
2019-05-31 07:50:16 +08:00
|
|
|
}
|
2019-11-15 03:02:52 +08:00
|
|
|
|
|
|
|
LLVM_DEBUG(print(llvm::dbgs()));
|
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");
|
|
|
|
}
|
2019-11-15 03:02:52 +08:00
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
bool tblgen::Operator::hasAssemblyFormat() const {
|
|
|
|
auto *valueInit = def.getValueInit("assemblyFormat");
|
|
|
|
return isa<llvm::CodeInit>(valueInit) || isa<llvm::StringInit>(valueInit);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef tblgen::Operator::getAssemblyFormat() const {
|
|
|
|
return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat"))
|
|
|
|
.Case<llvm::StringInit, llvm::CodeInit>(
|
|
|
|
[&](auto *init) { return init->getValue(); });
|
|
|
|
}
|
|
|
|
|
2019-11-15 03:02:52 +08:00
|
|
|
void tblgen::Operator::print(llvm::raw_ostream &os) const {
|
|
|
|
os << "op '" << getOperationName() << "'\n";
|
|
|
|
for (Argument arg : arguments) {
|
|
|
|
if (auto *attr = arg.dyn_cast<NamedAttribute *>())
|
|
|
|
os << "[attribute] " << attr->name << '\n';
|
|
|
|
else
|
|
|
|
os << "[operand] " << arg.get<NamedTypeConstraint *>()->name << '\n';
|
|
|
|
}
|
|
|
|
}
|
2020-03-07 05:55:36 +08:00
|
|
|
|
|
|
|
auto tblgen::Operator::VariableDecoratorIterator::unwrap(llvm::Init *init)
|
|
|
|
-> VariableDecorator {
|
|
|
|
return VariableDecorator(cast<llvm::DefInit>(init)->getDef());
|
|
|
|
}
|