This allows constructing operand adaptor from existing op (useful for commonalizing verification as I want to do in a follow up).
I also add ability to use member initializers for the generated adaptor constructors for convenience.
Differential Revision: https://reviews.llvm.org/D80667
// This is a strided getElementPtr variant that linearizes subscripts as:
// `base_offset + index_0 * stride_0 + ... + index_n * stride_n`.
Value getStridedElementPtr(Location loc, Type elementTypePtr,
- Value descriptor, ArrayRef<Value> indices,
+ Value descriptor, ValueRange indices,
ArrayRef<int64_t> strides, int64_t offset,
ConversionPatternRewriter &rewriter) const;
Value getDataPtr(Location loc, MemRefType type, Value memRefDesc,
- ArrayRef<Value> indices, ConversionPatternRewriter &rewriter,
+ ValueRange indices, ConversionPatternRewriter &rewriter,
llvm::Module &module) const;
protected:
// with AffineMap that has static strides. Extend to handle dynamic strides.
spirv::AccessChainOp getElementPtr(SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
- ArrayRef<Value> indices, Location loc,
+ ValueRange indices, Location loc,
OpBuilder &builder);
/// Sets the InterfaceVarABIAttr and EntryPointABIAttr for a function and its
OpMethod(StringRef retType, StringRef name, StringRef params,
Property property, bool declOnly);
+ virtual ~OpMethod() = default;
OpMethodBody &body();
bool isPrivate() const;
// Writes the method as a declaration to the given `os`.
- void writeDeclTo(raw_ostream &os) const;
+ virtual void writeDeclTo(raw_ostream &os) const;
// Writes the method as a definition to the given `os`. `namePrefix` is the
// prefix to be prepended to the method name (typically namespaces for
// qualifying the method definition).
- void writeDefTo(raw_ostream &os, StringRef namePrefix) const;
+ virtual void writeDefTo(raw_ostream &os, StringRef namePrefix) const;
-private:
+protected:
Property properties;
// Whether this method only contains a declaration.
bool isDeclOnly;
OpMethodBody methodBody;
};
+// Class for holding an op's constructor method for C++ code emission.
+class OpConstructor : public OpMethod {
+public:
+ OpConstructor(StringRef retType, StringRef name, StringRef params,
+ Property property, bool declOnly)
+ : OpMethod(retType, name, params, property, declOnly){};
+
+ // Add member initializer to constructor initializing `name` with `value`.
+ void addMemberInitializer(StringRef name, StringRef value);
+
+ // Writes the method as a definition to the given `os`. `namePrefix` is the
+ // prefix to be prepended to the method name (typically namespaces for
+ // qualifying the method definition).
+ void writeDefTo(raw_ostream &os, StringRef namePrefix) const override;
+
+private:
+ // Member initializers.
+ std::string memberInitializers;
+};
+
// A class used to emit C++ classes from Tablegen. Contains a list of public
// methods and a list of private fields to be emitted.
class Class {
OpMethod::Property = OpMethod::MP_None,
bool declOnly = false);
- OpMethod &newConstructor(StringRef params = "", bool declOnly = false);
+ OpConstructor &newConstructor(StringRef params = "", bool declOnly = false);
// Creates a new field in this class.
void newField(StringRef type, StringRef name, StringRef defaultValue = "");
protected:
std::string className;
+ SmallVector<OpConstructor, 2> constructors;
SmallVector<OpMethod, 8> methods;
SmallVector<std::string, 4> fields;
};
// Returns this op's C++ class name prefixed with namespaces.
std::string getQualCppClassName() const;
+ // Returns the name of op's adaptor C++ class.
+ std::string getAdaptorName() const;
+
/// A class used to represent the decorators of an operator variable, i.e.
/// argument or result.
struct VariableDecorator {
}
Value ConvertToLLVMPattern::getStridedElementPtr(
- Location loc, Type elementTypePtr, Value descriptor,
- ArrayRef<Value> indices, ArrayRef<int64_t> strides, int64_t offset,
+ Location loc, Type elementTypePtr, Value descriptor, ValueRange indices,
+ ArrayRef<int64_t> strides, int64_t offset,
ConversionPatternRewriter &rewriter) const {
MemRefDescriptor memRefDescriptor(descriptor);
}
Value ConvertToLLVMPattern::getDataPtr(Location loc, MemRefType type,
- Value memRefDesc,
- ArrayRef<Value> indices,
+ Value memRefDesc, ValueRange indices,
ConversionPatternRewriter &rewriter,
llvm::Module &module) const {
LLVM::LLVMType ptrType = MemRefDescriptor(memRefDesc).getElementType();
// Build and return the value for the idx^th shape dimension, either by
// returning the constant shape dimension or counting the proper dynamic size.
Value getSize(ConversionPatternRewriter &rewriter, Location loc,
- ArrayRef<int64_t> shape, ArrayRef<Value> dynamicSizes,
+ ArrayRef<int64_t> shape, ValueRange dynamicSizes,
unsigned idx) const {
assert(idx < shape.size());
if (!ShapedType::isDynamic(shape[idx]))
spirv::AccessChainOp mlir::spirv::getElementPtr(
SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr,
- ArrayRef<Value> indices, Location loc, OpBuilder &builder) {
+ ValueRange indices, Location loc, OpBuilder &builder) {
// Get base and offset of the MemRefType and verify they are static.
int64_t offset;
}
auto indexType = typeConverter.getIndexType(builder.getContext());
+
SmallVector<Value, 2> linearizedIndices;
// Add a '0' at the start to index into the struct.
auto zero = spirv::ConstantOp::getZero(indexType, loc, builder);
loc, indexType, IntegerAttr::get(indexType, offset));
assert(indices.size() == strides.size() &&
"must provide indices for all dimensions");
- for (auto index : enumerate(indices)) {
+ for (auto index : llvm::enumerate(indices)) {
Value strideVal = builder.create<spirv::ConstantOp>(
loc, indexType, IntegerAttr::get(indexType, strides[index.index()]));
Value update =
}
//===----------------------------------------------------------------------===//
+// OpConstructor definitions
+//===----------------------------------------------------------------------===//
+
+void mlir::tblgen::OpConstructor::addMemberInitializer(StringRef name,
+ StringRef value) {
+ memberInitializers.append(std::string(llvm::formatv(
+ "{0}{1}({2})", memberInitializers.empty() ? " : " : ", ", name, value)));
+}
+
+void mlir::tblgen::OpConstructor::writeDefTo(raw_ostream &os,
+ StringRef namePrefix) const {
+ if (isDeclOnly)
+ return;
+
+ methodSignature.writeDefTo(os, namePrefix);
+ os << " " << memberInitializers << " {\n";
+ methodBody.writeTo(os);
+ os << "}";
+}
+
+//===----------------------------------------------------------------------===//
// Class definitions
//===----------------------------------------------------------------------===//
return methods.back();
}
-tblgen::OpMethod &tblgen::Class::newConstructor(StringRef params,
- bool declOnly) {
- return newMethod("", getClassName(), params, OpMethod::MP_Constructor,
- declOnly);
+tblgen::OpConstructor &tblgen::Class::newConstructor(StringRef params,
+ bool declOnly) {
+ constructors.emplace_back("", getClassName(), params,
+ OpMethod::MP_Constructor, declOnly);
+ return constructors.back();
}
void tblgen::Class::newField(StringRef type, StringRef name,
bool hasPrivateMethod = false;
os << "class " << className << " {\n";
os << "public:\n";
- for (const auto &method : methods) {
+ for (const auto &method :
+ llvm::concat<const OpMethod>(constructors, methods)) {
if (!method.isPrivate()) {
method.writeDeclTo(os);
os << '\n';
os << '\n';
os << "private:\n";
if (hasPrivateMethod) {
- for (const auto &method : methods) {
+ for (const auto &method :
+ llvm::concat<const OpMethod>(constructors, methods)) {
if (method.isPrivate()) {
method.writeDeclTo(os);
os << '\n';
}
void tblgen::Class::writeDefTo(raw_ostream &os) const {
- for (const auto &method : methods) {
+ for (const auto &method :
+ llvm::concat<const OpMethod>(constructors, methods)) {
method.writeDefTo(os, className);
os << "\n\n";
}
return std::string(llvm::formatv("{0}.{1}", prefix, opName));
}
+std::string tblgen::Operator::getAdaptorName() const {
+ return std::string(llvm::formatv("{0}OperandAdaptor", getCppClassName()));
+}
+
StringRef tblgen::Operator::getDialectName() const { return dialect.getName(); }
StringRef tblgen::Operator::getCppClassName() const { return cppClassName; }
// CHECK: class AOpOperandAdaptor {
// CHECK: public:
-// CHECK: AOpOperandAdaptor(ArrayRef<Value> values
-// CHECK: ArrayRef<Value> getODSOperands(unsigned index);
+// CHECK: AOpOperandAdaptor(ValueRange values
+// CHECK: ValueRange getODSOperands(unsigned index);
// CHECK: Value a();
-// CHECK: ArrayRef<Value> b();
+// CHECK: ValueRange b();
// CHECK: IntegerAttr attr1();
// CHECL: FloatAttr attr2();
// CHECK: private:
-// CHECK: ArrayRef<Value> odsOperands;
+// CHECK: ValueRange odsOperands;
// CHECK: };
// CHECK: class AOp : public Op<AOp, OpTrait::AtLeastNRegions<1>::Impl, OpTrait::AtLeastNResults<1>::Impl, OpTrait::ZeroSuccessor, OpTrait::AtLeastNOperands<1>::Impl, OpTrait::IsIsolatedFromAbove
}
// CHECK-LABEL: AttrSizedOperandOpOperandAdaptor(
-// CHECK-SAME: ArrayRef<Value> values
+// CHECK-SAME: ValueRange values
// CHECK-SAME: DictionaryAttr attrs
-// CHECK: ArrayRef<Value> a();
-// CHECK: ArrayRef<Value> b();
+// CHECK: ValueRange a();
+// CHECK: ValueRange b();
// CHECK: Value c();
-// CHECK: ArrayRef<Value> d();
+// CHECK: ValueRange d();
// CHECK: DenseIntElementsAttr operand_segment_sizes();
// Check op trait for different number of operands
// CHECK-LABEL: OpA definitions
// CHECK: OpAOperandAdaptor::OpAOperandAdaptor
-// CHECK-NEXT: odsOperands = values
+// CHECK-SAME: odsOperands(values), odsAttrs(attrs)
// CHECK: void OpA::build
// CHECK: Value input
let arguments = (ins Variadic<AnyTensor>:$input1, AnyTensor:$input2, Variadic<AnyTensor>:$input3);
}
-// CHECK-LABEL: ArrayRef<Value> OpDOperandAdaptor::input1
+// CHECK-LABEL: ValueRange OpDOperandAdaptor::input1
// CHECK-NEXT: return getODSOperands(0);
// CHECK-LABEL: Value OpDOperandAdaptor::input2
// CHECK-NEXT: return *getODSOperands(1).begin();
-// CHECK-LABEL: ArrayRef<Value> OpDOperandAdaptor::input3
+// CHECK-LABEL: ValueRange OpDOperandAdaptor::input3
// CHECK-NEXT: return getODSOperands(2);
// CHECK-LABEL: Operation::operand_range OpD::input1
private:
explicit OpOperandAdaptorEmitter(const Operator &op);
- Class adapterClass;
+ Class adaptor;
};
} // end namespace
OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(const Operator &op)
- : adapterClass(op.getCppClassName().str() + "OperandAdaptor") {
- adapterClass.newField("ArrayRef<Value>", "odsOperands");
- adapterClass.newField("DictionaryAttr", "odsAttrs");
+ : adaptor(op.getAdaptorName()) {
+ adaptor.newField("ValueRange", "odsOperands");
+ adaptor.newField("DictionaryAttr", "odsAttrs");
const auto *attrSizedOperands =
op.getTrait("OpTrait::AttrSizedOperandSegments");
- auto &constructor = adapterClass.newConstructor(
- attrSizedOperands
- ? "ArrayRef<Value> values, DictionaryAttr attrs"
- : "ArrayRef<Value> values, DictionaryAttr attrs = nullptr");
- constructor.body() << " odsOperands = values;\n";
- constructor.body() << " odsAttrs = attrs;\n";
+ {
+ auto &constructor = adaptor.newConstructor(
+ attrSizedOperands
+ ? "ValueRange values, DictionaryAttr attrs"
+ : "ValueRange values, DictionaryAttr attrs = nullptr");
+ constructor.addMemberInitializer("odsOperands", "values");
+ constructor.addMemberInitializer("odsAttrs", "attrs");
+ }
+
+ {
+ auto &constructor = adaptor.newConstructor(
+ llvm::formatv("{0}& op", op.getCppClassName()).str());
+ constructor.addMemberInitializer("odsOperands",
+ "op.getOperation()->getOperands()");
+ constructor.addMemberInitializer("odsAttrs",
+ "op.getOperation()->getAttrDictionary()");
+ }
std::string sizeAttrInit =
formatv(adapterSegmentSizeAttrInitCode, "operand_segment_sizes");
- generateNamedOperandGetters(op, adapterClass, sizeAttrInit,
- /*rangeType=*/"ArrayRef<Value>",
+ generateNamedOperandGetters(op, adaptor, sizeAttrInit,
+ /*rangeType=*/"ValueRange",
/*rangeBeginCall=*/"odsOperands.begin()",
/*rangeSizeCall=*/"odsOperands.size()",
/*getOperandCallPattern=*/"odsOperands[{0}]");
fctx.withBuilder("mlir::Builder(odsAttrs.getContext())");
auto emitAttr = [&](StringRef name, Attribute attr) {
- auto &body = adapterClass.newMethod(attr.getStorageType(), name).body();
+ auto &body = adaptor.newMethod(attr.getStorageType(), name).body();
body << " assert(odsAttrs && \"no attributes when constructing adapter\");"
<< "\n " << attr.getStorageType() << " attr = "
<< "odsAttrs.get(\"" << name << "\").";
}
void OpOperandAdaptorEmitter::emitDecl(const Operator &op, raw_ostream &os) {
- OpOperandAdaptorEmitter(op).adapterClass.writeDeclTo(os);
+ OpOperandAdaptorEmitter(op).adaptor.writeDeclTo(os);
}
void OpOperandAdaptorEmitter::emitDef(const Operator &op, raw_ostream &os) {
- OpOperandAdaptorEmitter(op).adapterClass.writeDefTo(os);
+ OpOperandAdaptorEmitter(op).adaptor.writeDefTo(os);
}
// Emits the opcode enum and op classes.