// (variadic or not).
//
// {0}: The name of the attribute specifying the segment sizes.
-const char *attrSizedSegmentValueRangeCalcCode = R"(
+const char *adapterSegmentSizeAttrInitCode = R"(
+ assert(odsAttrs && "missing segment size attribute for op");
+ auto sizeAttr = odsAttrs.get("{0}").cast<DenseIntElementsAttr>();
+)";
+const char *opSegmentSizeAttrInitCode = R"(
auto sizeAttr = getAttrOfType<DenseIntElementsAttr>("{0}");
+)";
+const char *attrSizedSegmentValueRangeCalcCode = R"(
unsigned start = 0;
for (unsigned i = 0; i < index; ++i)
start += (*(sizeAttr.begin() + i)).getZExtValue();
unsigned size = (*(sizeAttr.begin() + index)).getZExtValue();
- return {{start, size};
+ return {start, size};
)";
// The logic to build a range of either operand or result values.
generateValueRangeStartAndEnd(Class &opClass, StringRef methodName,
int numVariadic, int numNonVariadic,
StringRef rangeSizeCall, bool hasAttrSegmentSize,
- StringRef segmentSizeAttr, RangeT &&odsValues) {
+ StringRef sizeAttrInit, RangeT &&odsValues) {
auto &method = opClass.newMethod("std::pair<unsigned, unsigned>", methodName,
"unsigned index");
if (numVariadic == 0) {
method.body() << " return {index, 1};\n";
} else if (hasAttrSegmentSize) {
- method.body() << formatv(attrSizedSegmentValueRangeCalcCode,
- segmentSizeAttr);
+ method.body() << sizeAttrInit << attrSizedSegmentValueRangeCalcCode;
} else {
// Because the op can have arbitrarily interleaved variadic and non-variadic
// operands, we need to embed a list in the "sink" getter method for
// of ops, in particular for one-operand ops that may not have the
// `getOperand(unsigned)` method.
static void generateNamedOperandGetters(const Operator &op, Class &opClass,
+ StringRef sizeAttrInit,
StringRef rangeType,
StringRef rangeBeginCall,
StringRef rangeSizeCall,
// First emit a few "sink" getter methods upon which we layer all nicer named
// getter methods.
- generateValueRangeStartAndEnd(
- opClass, "getODSOperandIndexAndLength", numVariadicOperands,
- numNormalOperands, rangeSizeCall, attrSizedOperands,
- "operand_segment_sizes", const_cast<Operator &>(op).getOperands());
+ generateValueRangeStartAndEnd(opClass, "getODSOperandIndexAndLength",
+ numVariadicOperands, numNormalOperands,
+ rangeSizeCall, attrSizedOperands, sizeAttrInit,
+ const_cast<Operator &>(op).getOperands());
auto &m = opClass.newMethod(rangeType, "getODSOperands", "unsigned index");
m.body() << formatv(valueRangeReturnCode, rangeBeginCall,
// Then we emit nicer named getter methods by redirecting to the "sink" getter
// method.
-
for (int i = 0; i != numOperands; ++i) {
const auto &operand = op.getOperand(i);
if (operand.name.empty())
}
void OpEmitter::genNamedOperandGetters() {
- if (op.getTrait("OpTrait::AttrSizedOperandSegments"))
- opClass.setHasOperandAdaptorClass(false);
-
generateNamedOperandGetters(
- op, opClass, /*rangeType=*/"Operation::operand_range",
+ op, opClass,
+ /*sizeAttrInit=*/
+ formatv(opSegmentSizeAttrInitCode, "operand_segment_sizes").str(),
+ /*rangeType=*/"Operation::operand_range",
/*rangeBeginCall=*/"getOperation()->operand_begin()",
/*rangeSizeCall=*/"getOperation()->getNumOperands()",
/*getOperandCallPattern=*/"getOperation()->getOperand({0})");
generateValueRangeStartAndEnd(
opClass, "getODSResultIndexAndLength", numVariadicResults,
numNormalResults, "getOperation()->getNumResults()", attrSizedResults,
- "result_segment_sizes", op.getResults());
+ formatv(opSegmentSizeAttrInitCode, "result_segment_sizes").str(),
+ op.getResults());
auto &m = opClass.newMethod("Operation::result_range", "getODSResults",
"unsigned index");
m.body() << formatv(valueRangeReturnCode, "getOperation()->result_begin()",
OpOperandAdaptorEmitter::OpOperandAdaptorEmitter(const Operator &op)
: adapterClass(op.getCppClassName().str() + "OperandAdaptor") {
- adapterClass.newField("ArrayRef<Value>", "tblgen_operands");
- auto &constructor = adapterClass.newConstructor("ArrayRef<Value> values");
- constructor.body() << " tblgen_operands = values;\n";
-
- generateNamedOperandGetters(op, adapterClass,
+ adapterClass.newField("ArrayRef<Value>", "odsOperands");
+ adapterClass.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";
+
+ std::string sizeAttrInit =
+ formatv(adapterSegmentSizeAttrInitCode, "operand_segment_sizes");
+ generateNamedOperandGetters(op, adapterClass, sizeAttrInit,
/*rangeType=*/"ArrayRef<Value>",
- /*rangeBeginCall=*/"tblgen_operands.begin()",
- /*rangeSizeCall=*/"tblgen_operands.size()",
- /*getOperandCallPattern=*/"tblgen_operands[{0}]");
+ /*rangeBeginCall=*/"odsOperands.begin()",
+ /*rangeSizeCall=*/"odsOperands.size()",
+ /*getOperandCallPattern=*/"odsOperands[{0}]");
+
+ FmtContext fctx;
+ fctx.withBuilder("mlir::Builder(odsAttrs.getContext())");
+
+ auto emitAttr = [&](StringRef name, Attribute attr) {
+ auto &body = adapterClass.newMethod(attr.getStorageType(), name).body();
+ body << " assert(odsAttrs && \"no attributes when constructing adapter\");"
+ << "\n " << attr.getStorageType() << " attr = "
+ << "odsAttrs.get(\"" << name << "\").";
+ if (attr.hasDefaultValue() || attr.isOptional())
+ body << "dyn_cast_or_null<";
+ else
+ body << "cast<";
+ body << attr.getStorageType() << ">();\n";
+
+ if (attr.hasDefaultValue()) {
+ // Use the default value if attribute is not set.
+ // TODO: this is inefficient, we are recreating the attribute for every
+ // call. This should be set instead.
+ std::string defaultValue = std::string(
+ tgfmt(attr.getConstBuilderTemplate(), &fctx, attr.getDefaultValue()));
+ body << " if (!attr)\n attr = " << defaultValue << ";\n";
+ }
+ body << " return attr;\n";
+ };
+
+ for (auto &namedAttr : op.getAttributes()) {
+ const auto &name = namedAttr.name;
+ const auto &attr = namedAttr.attr;
+ if (!attr.isDerivedAttr())
+ emitAttr(name, attr);
+ }
}
void OpOperandAdaptorEmitter::emitDecl(const Operator &op, raw_ostream &os) {
}
for (auto *def : defs) {
Operator op(*def);
- const auto *attrSizedOperands =
- op.getTrait("OpTrait::AttrSizedOperandSegments");
if (emitDecl) {
os << formatv(opCommentHeader, op.getQualCppClassName(), "declarations");
- // We cannot generate the operand adaptor class if operand getters depend
- // on an attribute.
- if (!attrSizedOperands)
- OpOperandAdaptorEmitter::emitDecl(op, os);
+ OpOperandAdaptorEmitter::emitDecl(op, os);
OpEmitter::emitDecl(op, os);
} else {
os << formatv(opCommentHeader, op.getQualCppClassName(), "definitions");
- if (!attrSizedOperands)
- OpOperandAdaptorEmitter::emitDef(op, os);
+ OpOperandAdaptorEmitter::emitDef(op, os);
OpEmitter::emitDef(op, os);
}
}