Create OpTrait base class & allow operation predicate OpTraits.

* Introduce a OpTrait class in C++ to wrap the TableGen definition;
* Introduce PredOpTrait and rename previous usage of OpTrait to NativeOpTrait;
* PredOpTrait allows specifying a trait of the operation by way of predicate on the operation. This will be used in future to create reusable set of trait building blocks in the definition of operations. E.g., indicating whether to operands have the same type and allowing locally documenting op requirements by trait composition.
  - Some of these building blocks could later evolve into known fixed set as LLVMs backends do, but that can be considered with more data.
* Use the modelling to address one verify TODO in a very local manner.

This subsumes the current custom verify specification which will be removed in a separate mechanical CL.

PiperOrigin-RevId: 234827169
This commit is contained in:
Jacques Pienaar 2019-02-20 10:50:26 -08:00 committed by jpienaar
parent 61d848da07
commit 1725b485eb
6 changed files with 212 additions and 23 deletions

View File

@ -364,24 +364,33 @@ class ConstF32Attr<string val> : ConstantAttr<F32Attr, val>;
// Op Traits
//===----------------------------------------------------------------------===//
// OpTrait represents a trait regarding an op. It corresponds to the MLIR C++
// OpTrait mechanism. The purpose to wrap around C++ symbol string with this
// class is to make traits specified for ops in TableGen less alien and more
// OpTrait represents a trait regarding an op.
class OpTrait;
// NativeOpTrait corresponds to the MLIR C++ OpTrait mechanism. The
// purpose to wrap around C++ symbol string with this class is to make
// traits specified for ops in TableGen less alien and more
// integrated.
class OpTrait<string prop> {
class NativeOpTrait<string prop> : OpTrait {
string trait = prop;
}
// Specify a trait by way of a predicate on the operation.
class PredOpTrait<string d, Pred p> : OpTrait {
string desc = d;
Pred pred = p;
}
// op supports operand broadcast behavior
def Broadcastable : OpTrait<"BroadcastableTwoOperandsOneResult">;
def Broadcastable : NativeOpTrait<"BroadcastableTwoOperandsOneResult">;
// X op Y == Y op X
def Commutative : OpTrait<"IsCommutative">;
def Commutative : NativeOpTrait<"IsCommutative">;
// op has no side effect
def NoSideEffect : OpTrait<"HasNoSideEffect">;
def NoSideEffect : NativeOpTrait<"HasNoSideEffect">;
// op has the same operand and result type
def SameValueType : OpTrait<"SameOperandsAndResultType">;
def SameValueType : NativeOpTrait<"SameOperandsAndResultType">;
// op is a terminator
def Terminator : OpTrait<"IsTerminator">;
def Terminator : NativeOpTrait<"IsTerminator">;
//===----------------------------------------------------------------------===//
// Ops
@ -457,9 +466,7 @@ class Op<string mnemonic, list<OpTrait> props = []> {
bit hasFolder = 0b0;
// Op traits.
list<string> traits = !foldl(
// Collect all OpTrait's internal strings into a list
[]<string>, props, prev, cur, !listconcat(prev, [cur.trait]));
list<OpTrait> traits = props;
}
// The arguments of an op.

View File

@ -0,0 +1,85 @@
//===- OpTrait.h - OpTrait wrapper class ------------------------*- C++ -*-===//
//
// 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.
// =============================================================================
//
// OpTrait wrapper to simplify using TableGen Record defining an MLIR OpTrait.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_TABLEGEN_OPTRAIT_H_
#define MLIR_TABLEGEN_OPTRAIT_H_
#include "mlir/Support/LLVM.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
class Init;
class Record;
} // end namespace llvm
namespace mlir {
namespace tblgen {
// Wrapper class with helper methods for accessing OpTrait constraints defined
// in TableGen.
class OpTrait {
public:
// Discriminator for kinds of op traits.
enum class Kind {
// OpTrait corresponding to C++ class.
Native,
// OpTrait corresponding to predicate on operation.
Pred,
};
explicit OpTrait(Kind kind, const llvm::Record *def);
// Returns an OpTrait corresponding to the init provided.
static OpTrait create(const llvm::Init *init);
Kind getKind() const { return kind; }
protected:
// The TableGen definition of this trait.
const llvm::Record *def;
Kind kind;
};
// OpTrait corresponding to a native C++ OpTrait.
class NativeOpTrait : public OpTrait {
public:
// Returns the trait corresponding to a C++ trait class.
StringRef getTrait() const;
static bool classof(const OpTrait *t) { return t->getKind() == Kind::Native; }
};
// OpTrait corresponding to a predicate on the operation.
class PredOpTrait : public OpTrait {
public:
// Returns the template for constructing the predicate.
std::string getPredTemplate() const;
// Returns the description of what the predicate is verifying.
StringRef getDescription() const;
static bool classof(const OpTrait *t) { return t->getKind() == Kind::Pred; }
};
} // end namespace tblgen
} // end namespace mlir
#endif // MLIR_TABLEGEN_OPTRAIT_H_

View File

@ -25,6 +25,7 @@
#include "mlir/Support/LLVM.h"
#include "mlir/TableGen/Argument.h"
#include "mlir/TableGen/Attribute.h"
#include "mlir/TableGen/OpTrait.h"
#include "mlir/TableGen/Type.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
@ -97,8 +98,6 @@ public:
llvm::iterator_range<operand_iterator> getOperands();
int getNumOperands() const { return operands.size(); }
// Op operand accessors.
Value &getOperand(int index) { return operands[index]; }
const Value &getOperand(int index) const { return operands[index]; }
@ -117,6 +116,12 @@ public:
// requiring the raw MLIR trait here.
bool hasTrait(llvm::StringRef trait) const;
// Trait.
using const_trait_iterator = const OpTrait *;
const_trait_iterator trait_begin() const;
const_trait_iterator trait_end() const;
llvm::iterator_range<const_trait_iterator> getTraits() const;
ArrayRef<llvm::SMLoc> getLoc() const;
// Query functions for the documentation of the operator.
@ -126,7 +131,7 @@ public:
StringRef getSummary() const;
private:
// Populates the vectors containing operands, attributes, and results.
// Populates the vectors containing operands, attributes, results and traits.
void populateOpStructure();
// The name of the op split around '_'.
@ -141,6 +146,9 @@ private:
// The results of the op.
SmallVector<Value, 4> results;
// The traits of the op.
SmallVector<OpTrait, 4> traits;
// The start of native attributes, which are specified when creating the op
// as a part of the op's definition.
int nativeAttrStart;

View File

@ -0,0 +1,53 @@
//===- OpTrait.cpp - OpTrait 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.
// =============================================================================
//
// OpTrait wrapper to simplify using TableGen Record defining a MLIR OpTrait.
//
//===----------------------------------------------------------------------===//
#include "mlir/TableGen/OpTrait.h"
#include "mlir/TableGen/Predicate.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace mlir;
mlir::tblgen::OpTrait mlir::tblgen::OpTrait::create(const llvm::Init *init) {
auto def = cast<llvm::DefInit>(init)->getDef();
if (def->isSubClassOf("PredOpTrait"))
return OpTrait(Kind::Pred, def);
assert(def->isSubClassOf("NativeOpTrait"));
return OpTrait(Kind::Native, def);
}
mlir::tblgen::OpTrait::OpTrait(Kind kind, const llvm::Record *def)
: def(def), kind(kind){};
llvm::StringRef mlir::tblgen::NativeOpTrait::getTrait() const {
return def->getValueAsString("trait");
}
std::string mlir::tblgen::PredOpTrait::getPredTemplate() const {
auto pred = tblgen::Pred(def->getValueInit("pred"));
return pred.getCondition();
}
llvm::StringRef mlir::tblgen::PredOpTrait::getDescription() const {
return def->getValueAsString("desc");
}

View File

@ -20,6 +20,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/TableGen/Operator.h"
#include "mlir/TableGen/OpTrait.h"
#include "mlir/TableGen/Predicate.h"
#include "mlir/TableGen/Type.h"
#include "llvm/ADT/StringExtras.h"
@ -63,11 +64,13 @@ int tblgen::Operator::getNumResults() const {
}
tblgen::Type tblgen::Operator::getResultType(int index) const {
return results[index].type;
DagInit *results = def.getValueAsDag("results");
return Type(cast<DefInit>(results->getArg(index)));
}
StringRef tblgen::Operator::getResultName(int index) const {
return results[index].name;
DagInit *results = def.getValueAsDag("results");
return results->getArgNameStr(index);
}
bool tblgen::Operator::hasVariadicResult() const {
@ -96,12 +99,25 @@ StringRef tblgen::Operator::getArgName(int index) const {
}
bool tblgen::Operator::hasTrait(StringRef trait) const {
auto traits = def.getValueAsListOfStrings("traits");
if (std::find(traits.begin(), traits.end(), trait) != traits.end())
return true;
for (auto t : getTraits()) {
if (auto opTrait = dyn_cast<tblgen::NativeOpTrait>(&t))
if (opTrait->getTrait() == trait)
return true;
}
return false;
}
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()};
}
auto tblgen::Operator::attribute_begin() const -> attribute_iterator {
return attributes.begin();
}
@ -223,6 +239,13 @@ void tblgen::Operator::populateOpStructure() {
PrintFatalError(def.getLoc(),
"only the last result allowed to be variadic");
}
auto traitListInit = def.getValueAsListInit("traits");
if (!traitListInit)
return;
traits.reserve(traitListInit->size());
for (auto traitInit : *traitListInit)
traits.push_back(OpTrait::create(traitInit));
}
ArrayRef<llvm::SMLoc> tblgen::Operator::getLoc() const { return def.getLoc(); }

View File

@ -21,6 +21,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/TableGen/GenInfo.h"
#include "mlir/TableGen/OpTrait.h"
#include "mlir/TableGen/Operator.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormatVariadic.h"
@ -509,6 +510,17 @@ void OpEmitter::emitVerifier() {
++opIndex;
}
for (auto &trait : op.getTraits()) {
if (auto t = dyn_cast<tblgen::PredOpTrait>(&trait)) {
OUT(4) << "if (!"
<< formatv(t->getPredTemplate().c_str(),
"(*this->getInstruction())")
<< ")\n";
OUT(6) << "return emitOpError(\"failed to verify that "
<< t->getDescription() << "\");\n";
}
}
if (hasCustomVerify)
OUT(4) << codeInit->getValue() << "\n";
else
@ -541,11 +553,12 @@ void OpEmitter::emitTraits() {
}
}
// Add variadic size trait and normal op traits.
for (StringRef trait : def.getValueAsListOfStrings("traits")) {
os << ", OpTrait::" << trait;
for (const auto &trait : op.getTraits()) {
if (auto opTrait = dyn_cast<tblgen::NativeOpTrait>(&trait))
os << ", OpTrait::" << opTrait->getTrait();
}
// Add variadic size trait and normal op traits.
auto numOperands = op.getNumOperands();
bool hasVariadicOperand = op.hasVariadicOperand();