mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 06:06:34 +08:00
MLIR has support for type-polymorphic instructions, i.e. instructions that may take arguments of different types. For example, standard arithmetic operands take scalars, vectors or tensors. In order to express such instructions in TableGen, we need to be able to verify that a type object satisfies certain constraints, but we don't need to construct an instance of this type. The existing TableGen definition of Type requires both. Extract out a TypeConstraint TableGen class to define restrictions on types. Define the Type TableGen class as a subclass of TypeConstraint for consistency. Accept records of the TypeConstraint class instead of the Type class as values in the Arguments class when defining operators. Replace the predicate logic TableGen class based on conjunctive normal form with the predicate logic classes allowing for abitrary combinations of predicates using Boolean operators (AND/OR/NOT). The combination is implemented using simple string rewriting of C++ expressions and, therefore, respects the short-circuit evaluation order. No logic simplification is performed at the TableGen level so all expressions must be valid C++. Maintaining CNF using TableGen only would have been complicated when one needed to introduce top-level disjunction. It is also unclear if it could lead to a significantly simpler emitted C++ code. In the future, we may replace inplace predicate string combination with a tree structure that can be simplified in TableGen's C++ driver. Combined, these changes allow one to express traits like ArgumentsAreFloatLike directly in TableGen instead of relying on C++ trait classes. PiperOrigin-RevId: 229398247
168 lines
5.7 KiB
C++
168 lines
5.7 KiB
C++
//===- 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.
|
|
// =============================================================================
|
|
//
|
|
// Operator wrapper to simplify using TableGen Record defining a MLIR Op.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/TableGen/Operator.h"
|
|
#include "mlir/TableGen/Predicate.h"
|
|
#include "mlir/TableGen/Type.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
using namespace mlir;
|
|
|
|
using llvm::DagInit;
|
|
using llvm::DefInit;
|
|
using llvm::Record;
|
|
|
|
tblgen::Operator::Operator(const llvm::Record &def) : def(def) {
|
|
SplitString(def.getName(), splittedDefName, "_");
|
|
populateOperandsAndAttributes();
|
|
}
|
|
|
|
const SmallVectorImpl<StringRef> &tblgen::Operator::getSplitDefName() const {
|
|
return splittedDefName;
|
|
}
|
|
|
|
StringRef tblgen::Operator::getOperationName() const {
|
|
return def.getValueAsString("opName");
|
|
}
|
|
|
|
StringRef tblgen::Operator::cppClassName() const {
|
|
return getSplitDefName().back();
|
|
}
|
|
std::string tblgen::Operator::qualifiedCppClassName() const {
|
|
return llvm::join(getSplitDefName(), "::");
|
|
}
|
|
|
|
StringRef tblgen::Operator::getArgName(int index) const {
|
|
DagInit *argumentValues = def.getValueAsDag("arguments");
|
|
return argumentValues->getArgName(index)->getValue();
|
|
}
|
|
|
|
auto tblgen::Operator::attribute_begin() -> attribute_iterator {
|
|
return attributes.begin();
|
|
}
|
|
auto tblgen::Operator::attribute_end() -> attribute_iterator {
|
|
return attributes.end();
|
|
}
|
|
auto tblgen::Operator::getAttributes()
|
|
-> llvm::iterator_range<attribute_iterator> {
|
|
return {attribute_begin(), attribute_end()};
|
|
}
|
|
|
|
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> {
|
|
return {operand_begin(), operand_end()};
|
|
}
|
|
|
|
auto tblgen::Operator::getArg(int index) -> Argument {
|
|
if (index < nativeAttrStart)
|
|
return {&operands[index]};
|
|
return {&attributes[index - nativeAttrStart]};
|
|
}
|
|
|
|
void tblgen::Operator::populateOperandsAndAttributes() {
|
|
auto &recordKeeper = def.getRecords();
|
|
auto attrClass = recordKeeper.getClass("Attr");
|
|
auto derivedAttrClass = recordKeeper.getClass("DerivedAttr");
|
|
derivedAttrStart = -1;
|
|
|
|
// The argument ordering is operands, native attributes, derived
|
|
// attributes.
|
|
DagInit *argumentValues = def.getValueAsDag("arguments");
|
|
unsigned i = 0;
|
|
// Handle operands.
|
|
for (unsigned e = argumentValues->getNumArgs(); i != e; ++i) {
|
|
auto arg = argumentValues->getArg(i);
|
|
auto givenName = argumentValues->getArgName(i);
|
|
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;
|
|
operands.push_back(Operand{givenName, argDefInit});
|
|
}
|
|
|
|
// Handle native attributes.
|
|
nativeAttrStart = i;
|
|
for (unsigned e = argumentValues->getNumArgs(); i != e; ++i) {
|
|
auto arg = argumentValues->getArg(i);
|
|
auto givenName = argumentValues->getArgName(i);
|
|
Record *argDef = cast<DefInit>(arg)->getDef();
|
|
if (!argDef->isSubClassOf(attrClass))
|
|
PrintFatalError(def.getLoc(),
|
|
Twine("expected attribute as argument ") + Twine(i));
|
|
|
|
if (!givenName)
|
|
PrintFatalError(argDef->getLoc(), "attributes must be named");
|
|
bool isDerived = argDef->isSubClassOf(derivedAttrClass);
|
|
if (isDerived)
|
|
PrintFatalError(def.getLoc(),
|
|
"derived attributes not allowed in argument list");
|
|
attributes.push_back({givenName, Attribute(argDef)});
|
|
}
|
|
|
|
// Handle derived attributes.
|
|
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) {
|
|
PrintFatalError(
|
|
def.getLoc(),
|
|
"unsupported attribute modelling, only single class expected");
|
|
}
|
|
attributes.push_back({cast<llvm::StringInit>(val.getNameInit()),
|
|
Attribute(cast<DefInit>(val.getValue()))});
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string tblgen::Operator::NamedAttribute::getName() const {
|
|
std::string ret = name->getAsUnquotedString();
|
|
// TODO(jpienaar): Revise this post dialect prefixing attribute discussion.
|
|
auto split = StringRef(ret).split("__");
|
|
if (split.second.empty())
|
|
return ret;
|
|
return llvm::join_items("$", split.first, split.second);
|
|
}
|
|
|
|
bool tblgen::Operator::Operand::hasMatcher() const {
|
|
return !tblgen::TypeConstraint(*defInit).getPredicate().isNull();
|
|
}
|
|
|
|
tblgen::TypeConstraint tblgen::Operator::Operand::getTypeConstraint() const {
|
|
return tblgen::TypeConstraint(*defInit);
|
|
}
|