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-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"
|
2018-12-29 04:02:08 +08:00
|
|
|
#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-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())
|
2019-05-21 00:33:10 +08:00
|
|
|
return opName;
|
|
|
|
return 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::getCppNamespaces() const {
|
|
|
|
return dialect.getCppNamespace();
|
2019-01-09 09:19:37 +08:00
|
|
|
}
|
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())
|
|
|
|
return cppClassName;
|
|
|
|
return 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-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
|
|
|
}
|
|
|
|
|
2019-04-26 05:45:37 +08:00
|
|
|
unsigned tblgen::Operator::getNumVariadicResults() const {
|
|
|
|
return std::count_if(
|
|
|
|
results.begin(), results.end(),
|
|
|
|
[](const NamedTypeConstraint &c) { return c.constraint.isVariadic(); });
|
2019-01-30 02:03:17 +08:00
|
|
|
}
|
|
|
|
|
2019-01-29 06:04:40 +08:00
|
|
|
int tblgen::Operator::getNumNativeAttributes() const {
|
2019-03-06 17:23:41 +08:00
|
|
|
return numNativeAttributes;
|
2019-01-29 06:04:40 +08:00
|
|
|
}
|
|
|
|
|
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-04-26 05:45:37 +08:00
|
|
|
unsigned tblgen::Operator::getNumVariadicOperands() const {
|
|
|
|
return std::count_if(
|
|
|
|
operands.begin(), operands.end(),
|
|
|
|
[](const NamedTypeConstraint &c) { return c.constraint.isVariadic(); });
|
2019-02-06 21:06:11 +08:00
|
|
|
}
|
|
|
|
|
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-04-04 19:29:58 +08:00
|
|
|
int tblgen::Operator::getNumPredOpTraits() const {
|
|
|
|
return std::count_if(traits.begin(), traits.end(), [](const OpTrait &trait) {
|
|
|
|
return isa<tblgen::PredOpTrait>(&trait);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-15 02:54:50 +08:00
|
|
|
bool tblgen::Operator::hasTrait(StringRef trait) const {
|
2019-02-21 02:50:26 +08:00
|
|
|
for (auto t : getTraits()) {
|
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)
|
|
|
|
return true;
|
2019-03-27 06:31:15 +08:00
|
|
|
} else if (auto opTrait = dyn_cast<tblgen::InternalOpTrait>(&t)) {
|
|
|
|
if (opTrait->getTrait() == trait)
|
|
|
|
return true;
|
|
|
|
}
|
2019-02-21 02:50:26 +08:00
|
|
|
}
|
2019-02-15 02:54:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-05-31 07:50:16 +08:00
|
|
|
tblgen::Operator::const_region_iterator tblgen::Operator::region_begin() const {
|
|
|
|
return regions.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
tblgen::Operator::const_region_iterator tblgen::Operator::region_end() const {
|
|
|
|
return regions.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::iterator_range<tblgen::Operator::const_region_iterator>
|
|
|
|
tblgen::Operator::getRegions() const {
|
|
|
|
return {region_begin(), region_end()};
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
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-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-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");
|
2019-03-06 17:23:41 +08:00
|
|
|
numNativeAttributes = 0;
|
2018-12-29 04:02:08 +08:00
|
|
|
|
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;
|
2019-03-06 17:23:41 +08:00
|
|
|
// Handle operands and native attributes.
|
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
|
|
|
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();
|
|
|
|
|
2019-03-06 17:23:41 +08:00
|
|
|
if (argDef->isSubClassOf(typeConstraintClass)) {
|
2019-03-18 22:54:20 +08:00
|
|
|
operands.push_back(
|
[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
|
|
|
NamedTypeConstraint{givenName, TypeConstraint(argDefInit)});
|
2019-03-06 17:23:41 +08:00
|
|
|
arguments.emplace_back(&operands.back());
|
|
|
|
} 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)});
|
|
|
|
arguments.emplace_back(&attributes.back());
|
|
|
|
++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-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);
|
|
|
|
auto *resultDef = dyn_cast<DefInit>(resultsDag->getArg(i));
|
|
|
|
if (!resultDef) {
|
|
|
|
PrintFatalError(def.getLoc(),
|
|
|
|
Twine("undefined type for result #") + Twine(i));
|
|
|
|
}
|
[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
|
|
|
}
|
|
|
|
|
2019-02-21 02:50:26 +08:00
|
|
|
auto traitListInit = def.getValueAsListInit("traits");
|
|
|
|
if (!traitListInit)
|
|
|
|
return;
|
|
|
|
traits.reserve(traitListInit->size());
|
|
|
|
for (auto traitInit : *traitListInit)
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
regions.push_back({name, Region(regionInit->getDef())});
|
|
|
|
}
|
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");
|
|
|
|
}
|