2019-05-15 06:03:48 +08:00
|
|
|
//===- Attribute.cpp - Attribute wrapper class ----------------------------===//
|
2019-01-10 05:50:20 +08:00
|
|
|
//
|
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
|
2019-01-10 05:50:20 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2019-01-10 05:50:20 +08:00
|
|
|
//
|
|
|
|
// Attribute wrapper to simplify using TableGen Record defining a MLIR
|
|
|
|
// Attribute.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-04-12 21:05:49 +08:00
|
|
|
#include "mlir/TableGen/Format.h"
|
2019-01-10 05:50:20 +08:00
|
|
|
#include "mlir/TableGen/Operator.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
|
|
|
|
using namespace mlir;
|
2020-08-12 08:47:07 +08:00
|
|
|
using namespace mlir::tblgen;
|
2019-01-10 05:50:20 +08:00
|
|
|
|
2019-04-12 21:05:49 +08:00
|
|
|
using llvm::DefInit;
|
|
|
|
using llvm::Init;
|
|
|
|
using llvm::Record;
|
|
|
|
using llvm::StringInit;
|
|
|
|
|
2019-01-10 05:50:20 +08:00
|
|
|
// Returns the initializer's value as string if the given TableGen initializer
|
|
|
|
// is a code or string initializer. Returns the empty StringRef otherwise.
|
2019-04-12 21:05:49 +08:00
|
|
|
static StringRef getValueAsString(const Init *init) {
|
2020-08-12 08:47:07 +08:00
|
|
|
if (const auto *str = dyn_cast<StringInit>(init))
|
2019-01-10 05:50:20 +08:00
|
|
|
return str->getValue().trim();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
AttrConstraint::AttrConstraint(const Record *record)
|
[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
|
|
|
: Constraint(Constraint::CK_Attr, record) {
|
2019-11-13 03:57:40 +08:00
|
|
|
assert(isSubClassOf("AttrConstraint") &&
|
2019-01-28 23:13:40 +08:00
|
|
|
"must be subclass of TableGen 'AttrConstraint' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool AttrConstraint::isSubClassOf(StringRef className) const {
|
2019-11-13 03:57:40 +08:00
|
|
|
return def->isSubClassOf(className);
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Attribute::Attribute(const Record *record) : AttrConstraint(record) {
|
2019-01-28 23:13:40 +08:00
|
|
|
assert(record->isSubClassOf("Attr") &&
|
|
|
|
"must be subclass of TableGen 'Attr' class");
|
|
|
|
}
|
2019-01-17 02:23:21 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Attribute::Attribute(const DefInit *init) : Attribute(init->getDef()) {}
|
2019-01-10 05:50:20 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::isDerivedAttr() const { return isSubClassOf("DerivedAttr"); }
|
2019-01-10 05:50:20 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::isTypeAttr() const { return isSubClassOf("TypeAttrBase"); }
|
2019-03-27 06:31:15 +08:00
|
|
|
|
2020-11-19 10:31:40 +08:00
|
|
|
bool Attribute::isSymbolRefAttr() const {
|
|
|
|
StringRef defName = def->getName();
|
|
|
|
if (defName == "SymbolRefAttr" || defName == "FlatSymbolRefAttr")
|
|
|
|
return true;
|
|
|
|
return isSubClassOf("SymbolRefAttr") || isSubClassOf("FlatSymbolRefAttr");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::isEnumAttr() const { return isSubClassOf("EnumAttrInfo"); }
|
2019-07-18 09:41:28 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getStorageType() const {
|
2019-01-17 02:23:21 +08:00
|
|
|
const auto *init = def->getValueInit("storageType");
|
2019-01-10 05:50:20 +08:00
|
|
|
auto type = getValueAsString(init);
|
|
|
|
if (type.empty())
|
|
|
|
return "Attribute";
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getReturnType() const {
|
2019-01-17 02:23:21 +08:00
|
|
|
const auto *init = def->getValueInit("returnType");
|
2019-01-10 05:50:20 +08:00
|
|
|
return getValueAsString(init);
|
|
|
|
}
|
|
|
|
|
2020-02-09 02:01:17 +08:00
|
|
|
// Return the type constraint corresponding to the type of this attribute, or
|
|
|
|
// None if this is not a TypedAttr.
|
2020-08-12 08:47:07 +08:00
|
|
|
llvm::Optional<Type> Attribute::getValueType() const {
|
2020-02-09 02:01:17 +08:00
|
|
|
if (auto *defInit = dyn_cast<llvm::DefInit>(def->getValueInit("valueType")))
|
2020-08-12 08:47:07 +08:00
|
|
|
return Type(defInit->getDef());
|
2020-02-09 02:01:17 +08:00
|
|
|
return llvm::None;
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getConvertFromStorageCall() const {
|
2019-01-17 02:23:21 +08:00
|
|
|
const auto *init = def->getValueInit("convertFromStorage");
|
2019-01-10 05:50:20 +08:00
|
|
|
return getValueAsString(init);
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::isConstBuildable() const {
|
2019-01-17 02:23:21 +08:00
|
|
|
const auto *init = def->getValueInit("constBuilderCall");
|
2019-01-17 01:23:14 +08:00
|
|
|
return !getValueAsString(init).empty();
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getConstBuilderTemplate() const {
|
2019-01-17 02:23:21 +08:00
|
|
|
const auto *init = def->getValueInit("constBuilderCall");
|
2019-01-17 01:23:14 +08:00
|
|
|
return getValueAsString(init);
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Attribute Attribute::getBaseAttr() const {
|
2019-07-16 19:33:54 +08:00
|
|
|
if (const auto *defInit =
|
|
|
|
llvm::dyn_cast<llvm::DefInit>(def->getValueInit("baseAttr"))) {
|
|
|
|
return Attribute(defInit).getBaseAttr();
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::hasDefaultValue() const {
|
2019-01-23 02:26:09 +08:00
|
|
|
const auto *init = def->getValueInit("defaultValue");
|
|
|
|
return !getValueAsString(init).empty();
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getDefaultValue() const {
|
2019-04-12 21:05:49 +08:00
|
|
|
const auto *init = def->getValueInit("defaultValue");
|
|
|
|
return getValueAsString(init);
|
Spike to define real math ops and lowering of one variant of add to corresponding integer ops.
The only reason in starting with a fixedpoint add is that it is the absolute simplest variant and illustrates the level of abstraction I'm aiming for.
The overall flow would be:
1. Determine quantization parameters (out of scope of this cl).
2. Source dialect rules to lower supported math ops to the quantization dialect (out of scope of this cl).
3. Quantization passes: [-quant-convert-const, -quant-lower-uniform-real-math, -quant-lower-unsupported-to-float] (the last one not implemented yet)
4. Target specific lowering of the integral arithmetic ops (roughly at the level of gemmlowp) to more fundamental operations (i.e. calls to gemmlowp, simd instructions, DSP instructions, etc).
How I'm doing this should facilitate implementation of just about any kind of backend except TFLite, which has a very course, adhoc surface area for its quantized kernels. Options there include (I'm not taking an opinion on this - just trying to provide options):
a) Not using any of this: just match q/dbarrier + tf math ops to the supported TFLite quantized op set.
b) Implement the more fundamental integer math ops on TFLite and convert to those instead of the current op set.
Note that I've hand-waved over the process of choosing appropriate quantization parameters. Getting to that next. As you can see, different implementations will likely have different magic combinations of specific math support, and we will need the target system that has been discussed for some of the esoteric cases (i.e. many DSPs only support POT fixedpoint).
Two unrelated changes to the overall goal of this CL and can be broken out of desired:
- Adding optional attribute support to TabelGen
- Allowing TableGen native rewrite hooks to return nullptr, signalling that no rewrite has been done.
PiperOrigin-RevId: 235267229
2019-02-23 07:11:00 +08:00
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool Attribute::isOptional() const { return def->getValueAsBit("isOptional"); }
|
2019-01-23 02:26:09 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getAttrDefName() const {
|
2019-07-16 19:33:54 +08:00
|
|
|
if (def->isAnonymous()) {
|
|
|
|
return getBaseAttr().def->getName();
|
|
|
|
}
|
2019-01-17 02:23:21 +08:00
|
|
|
return def->getName();
|
2019-01-17 01:23:14 +08:00
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef Attribute::getDerivedCodeBody() const {
|
2019-01-10 05:50:20 +08:00
|
|
|
assert(isDerivedAttr() && "only derived attribute has 'body' field");
|
2019-01-17 02:23:21 +08:00
|
|
|
return def->getValueAsString("body");
|
2019-01-10 05:50:20 +08:00
|
|
|
}
|
2019-02-02 07:40:22 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Dialect Attribute::getDialect() const {
|
2020-09-11 03:00:49 +08:00
|
|
|
const llvm::RecordVal *record = def->getValue("dialect");
|
|
|
|
if (record && record->getValue()) {
|
|
|
|
if (DefInit *init = dyn_cast<DefInit>(record->getValue()))
|
|
|
|
return Dialect(init->getDef());
|
|
|
|
}
|
|
|
|
return Dialect(nullptr);
|
2020-03-15 11:33:53 +08:00
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
ConstantAttr::ConstantAttr(const DefInit *init) : def(init->getDef()) {
|
2019-02-02 07:40:22 +08:00
|
|
|
assert(def->isSubClassOf("ConstantAttr") &&
|
|
|
|
"must be subclass of TableGen 'ConstantAttr' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Attribute ConstantAttr::getAttribute() const {
|
2019-02-02 07:40:22 +08:00
|
|
|
return Attribute(def->getValueAsDef("attr"));
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef ConstantAttr::getConstantValue() const {
|
2019-02-02 07:40:22 +08:00
|
|
|
return def->getValueAsString("value");
|
|
|
|
}
|
2019-04-01 23:58:53 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
EnumAttrCase::EnumAttrCase(const llvm::Record *record) : Attribute(record) {
|
2019-11-13 03:57:40 +08:00
|
|
|
assert(isSubClassOf("EnumAttrCaseInfo") &&
|
2019-07-01 20:26:14 +08:00
|
|
|
"must be subclass of TableGen 'EnumAttrInfo' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
EnumAttrCase::EnumAttrCase(const llvm::DefInit *init)
|
2019-12-27 01:15:26 +08:00
|
|
|
: EnumAttrCase(init->getDef()) {}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool EnumAttrCase::isStrCase() const { return isSubClassOf("StrEnumAttrCase"); }
|
2019-04-01 23:58:53 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttrCase::getSymbol() const {
|
2019-04-01 23:58:53 +08:00
|
|
|
return def->getValueAsString("symbol");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttrCase::getStr() const { return def->getValueAsString("str"); }
|
2020-01-25 00:51:10 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
int64_t EnumAttrCase::getValue() const { return def->getValueAsInt("value"); }
|
2019-06-08 23:39:07 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
const llvm::Record &EnumAttrCase::getDef() const { return *def; }
|
2020-01-03 02:19:19 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
EnumAttr::EnumAttr(const llvm::Record *record) : Attribute(record) {
|
2019-11-13 03:57:40 +08:00
|
|
|
assert(isSubClassOf("EnumAttrInfo") &&
|
2019-04-01 23:58:53 +08:00
|
|
|
"must be subclass of TableGen 'EnumAttr' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
EnumAttr::EnumAttr(const llvm::Record &record) : Attribute(&record) {}
|
2019-06-08 23:39:07 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
EnumAttr::EnumAttr(const llvm::DefInit *init) : EnumAttr(init->getDef()) {}
|
2019-04-01 23:58:53 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool EnumAttr::classof(const Attribute *attr) {
|
2020-01-03 02:19:19 +08:00
|
|
|
return attr->isSubClassOf("EnumAttrInfo");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
bool EnumAttr::isBitEnum() const { return isSubClassOf("BitEnumAttr"); }
|
2019-09-17 00:22:43 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getEnumClassName() const {
|
2019-04-01 23:58:53 +08:00
|
|
|
return def->getValueAsString("className");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getCppNamespace() const {
|
2019-06-08 23:39:07 +08:00
|
|
|
return def->getValueAsString("cppNamespace");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getUnderlyingType() const {
|
2019-06-08 23:39:07 +08:00
|
|
|
return def->getValueAsString("underlyingType");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getUnderlyingToSymbolFnName() const {
|
2019-06-22 05:51:58 +08:00
|
|
|
return def->getValueAsString("underlyingToSymbolFnName");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getStringToSymbolFnName() const {
|
2019-06-08 23:39:07 +08:00
|
|
|
return def->getValueAsString("stringToSymbolFnName");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getSymbolToStringFnName() const {
|
2019-06-08 23:39:07 +08:00
|
|
|
return def->getValueAsString("symbolToStringFnName");
|
|
|
|
}
|
2019-09-17 00:22:43 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getSymbolToStringFnRetType() const {
|
2019-09-17 00:22:43 +08:00
|
|
|
return def->getValueAsString("symbolToStringFnRetType");
|
|
|
|
}
|
2019-06-08 23:39:07 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef EnumAttr::getMaxEnumValFnName() const {
|
2019-06-20 07:09:57 +08:00
|
|
|
return def->getValueAsString("maxEnumValFnName");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
std::vector<EnumAttrCase> EnumAttr::getAllCases() const {
|
2019-04-01 23:58:53 +08:00
|
|
|
const auto *inits = def->getValueAsListInit("enumerants");
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
std::vector<EnumAttrCase> cases;
|
2019-04-01 23:58:53 +08:00
|
|
|
cases.reserve(inits->size());
|
|
|
|
|
|
|
|
for (const llvm::Init *init : *inits) {
|
2020-08-12 08:47:07 +08:00
|
|
|
cases.push_back(EnumAttrCase(cast<llvm::DefInit>(init)));
|
2019-04-01 23:58:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return cases;
|
|
|
|
}
|
2019-08-31 03:51:31 +08:00
|
|
|
|
2021-02-27 20:21:00 +08:00
|
|
|
bool EnumAttr::genSpecializedAttr() const {
|
|
|
|
return def->getValueAsBit("genSpecializedAttr");
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Record *EnumAttr::getBaseAttrClass() const {
|
|
|
|
return def->getValueAsDef("baseAttrClass");
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef EnumAttr::getSpecializedAttrClassName() const {
|
|
|
|
return def->getValueAsString("specializedAttrClassName");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StructFieldAttr::StructFieldAttr(const llvm::Record *record) : def(record) {
|
2019-08-31 03:51:31 +08:00
|
|
|
assert(def->isSubClassOf("StructFieldAttr") &&
|
|
|
|
"must be subclass of TableGen 'StructFieldAttr' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StructFieldAttr::StructFieldAttr(const llvm::Record &record)
|
2019-08-31 03:51:31 +08:00
|
|
|
: StructFieldAttr(&record) {}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StructFieldAttr::StructFieldAttr(const llvm::DefInit *init)
|
2019-08-31 03:51:31 +08:00
|
|
|
: StructFieldAttr(init->getDef()) {}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef StructFieldAttr::getName() const {
|
2019-08-31 03:51:31 +08:00
|
|
|
return def->getValueAsString("name");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
Attribute StructFieldAttr::getType() const {
|
2019-08-31 03:51:31 +08:00
|
|
|
auto init = def->getValueInit("type");
|
2020-08-12 08:47:07 +08:00
|
|
|
return Attribute(cast<llvm::DefInit>(init));
|
2019-08-31 03:51:31 +08:00
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StructAttr::StructAttr(const llvm::Record *record) : Attribute(record) {
|
2019-11-13 03:57:40 +08:00
|
|
|
assert(isSubClassOf("StructAttr") &&
|
2019-08-31 03:51:31 +08:00
|
|
|
"must be subclass of TableGen 'StructAttr' class");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StructAttr::StructAttr(const llvm::DefInit *init)
|
2019-08-31 03:51:31 +08:00
|
|
|
: StructAttr(init->getDef()) {}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef StructAttr::getStructClassName() const {
|
2019-08-31 03:51:31 +08:00
|
|
|
return def->getValueAsString("className");
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
StringRef StructAttr::getCppNamespace() const {
|
2020-09-11 03:00:49 +08:00
|
|
|
Dialect dialect(def->getValueAsDef("dialect"));
|
2019-08-31 03:51:31 +08:00
|
|
|
return dialect.getCppNamespace();
|
|
|
|
}
|
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
std::vector<StructFieldAttr> StructAttr::getAllFields() const {
|
|
|
|
std::vector<StructFieldAttr> attributes;
|
2019-08-31 03:51:31 +08:00
|
|
|
|
|
|
|
const auto *inits = def->getValueAsListInit("fields");
|
|
|
|
attributes.reserve(inits->size());
|
|
|
|
|
|
|
|
for (const llvm::Init *init : *inits) {
|
|
|
|
attributes.emplace_back(cast<llvm::DefInit>(init));
|
|
|
|
}
|
|
|
|
|
|
|
|
return attributes;
|
|
|
|
}
|
2020-05-27 23:45:55 +08:00
|
|
|
|
2020-08-12 08:47:07 +08:00
|
|
|
const char * ::mlir::tblgen::inferTypeOpInterface = "InferTypeOpInterface";
|