20#include "llvm/ADT/APSInt.h"
21#include "llvm/Support/Debug.h"
22#include "llvm/Support/DebugLog.h"
23#include "llvm/Support/Endian.h"
26#define DEBUG_TYPE "builtinattributes"
35#define GET_ATTRDEF_CLASSES
36#include "mlir/IR/BuiltinAttributes.cpp.inc"
42void BuiltinDialect::registerAttributes() {
44#define GET_ATTRDEF_LIST
45#include "mlir/IR/BuiltinAttributes.cpp.inc"
47 addAttributes<DistinctAttr>();
58template <
bool inPlace>
62 switch (value.size()) {
71 storage.assign({value[0]});
74 bool isSorted = value[0] < value[1];
77 std::swap(storage[0], storage[1]);
78 }
else if (isSorted) {
79 storage.assign({value[0], value[1]});
81 storage.assign({value[1], value[0]});
87 storage.assign(value.begin(), value.end());
89 bool isSorted = llvm::is_sorted(value);
92 llvm::array_pod_sort(storage.begin(), storage.end());
100static std::optional<NamedAttribute>
102 const std::optional<NamedAttribute> none{std::nullopt};
103 if (value.size() < 2)
106 if (value.size() == 2)
107 return value[0].getName() == value[1].getName() ? value[0] : none;
109 const auto *it = std::adjacent_find(value.begin(), value.end(),
111 return l.getName() == r.getName();
113 return it != value.end() ? *it : none;
120 "DictionaryAttr element names must be unique");
127 "DictionaryAttr element names must be unique");
131std::optional<NamedAttribute>
139DictionaryAttr DictionaryAttr::get(
MLIRContext *context,
142 return DictionaryAttr::getEmpty(context);
145 SmallVector<NamedAttribute, 8> storage;
149 "DictionaryAttr element names must be unique");
150 return Base::get(context, value);
154DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
157 return DictionaryAttr::getEmpty(context);
159 assert(llvm::is_sorted(
160 value, [](NamedAttribute l, NamedAttribute r) {
return l < r; }) &&
161 "expected attribute values to be sorted");
163 "DictionaryAttr element names must be unique");
164 return Base::get(context, value);
168Attribute DictionaryAttr::get(StringRef name)
const {
169 auto it = impl::findAttrSorted(begin(), end(), name);
170 return it.second ? it.first->getValue() : Attribute();
172Attribute DictionaryAttr::get(StringAttr name)
const {
173 auto it = impl::findAttrSorted(begin(), end(), name);
174 return it.second ? it.first->getValue() : Attribute();
178std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
179 auto it = impl::findAttrSorted(begin(), end(), name);
180 return it.second ? *it.first : std::optional<NamedAttribute>();
182std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
183 auto it = impl::findAttrSorted(begin(), end(), name);
184 return it.second ? *it.first : std::optional<NamedAttribute>();
188bool DictionaryAttr::contains(StringRef name)
const {
189 return impl::findAttrSorted(begin(), end(), name).second;
191bool DictionaryAttr::contains(StringAttr name)
const {
192 return impl::findAttrSorted(begin(), end(), name).second;
195DictionaryAttr::iterator DictionaryAttr::begin()
const {
196 return getValue().begin();
198DictionaryAttr::iterator DictionaryAttr::end()
const {
199 return getValue().end();
201size_t DictionaryAttr::size()
const {
return getValue().size(); }
203DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
204 return Base::get(context, ArrayRef<NamedAttribute>());
212void StridedLayoutAttr::print(llvm::raw_ostream &os)
const {
213 auto printIntOrQuestion = [&](
int64_t value) {
214 if (ShapedType::isDynamic(value))
221 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
224 if (getOffset() != 0) {
226 printIntOrQuestion(getOffset());
233bool StridedLayoutAttr::hasStaticLayout()
const {
234 return ShapedType::isStatic(getOffset()) &&
235 ShapedType::isStaticShape(getStrides());
239AffineMap StridedLayoutAttr::getAffineMap()
const {
251LogicalResult StridedLayoutAttr::verifyLayout(
254 if (
shape.size() != getStrides().size())
255 return emitError() <<
"expected the number of strides to match the rank";
264 llvm::append_range(strides, getStrides());
265 offset = getOffset();
273StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
274 return Base::get(context,
"", NoneType::get(context));
278StringAttr StringAttr::get(
MLIRContext *context,
const Twine &twine) {
280 if (twine.isTriviallyEmpty())
282 SmallVector<char, 32> tempStr;
283 return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
287StringAttr StringAttr::get(
const Twine &twine,
Type type) {
288 SmallVector<char, 32> tempStr;
289 return Base::get(type.
getContext(), twine.toStringRef(tempStr), type);
292StringRef StringAttr::getValue()
const {
return getImpl()->value; }
294Type StringAttr::getType()
const {
return getImpl()->type; }
296Dialect *StringAttr::getReferencedDialect()
const {
297 return getImpl()->referencedDialect;
304double FloatAttr::getValueAsDouble()
const {
305 return getValueAsDouble(getValue());
307double FloatAttr::getValueAsDouble(APFloat value) {
308 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
309 bool losesInfo =
false;
310 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
313 return value.convertToDouble();
317 Type type, APFloat value) {
319 if (!llvm::isa<FloatType>(type))
320 return emitError() <<
"expected floating point type";
323 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
324 &value.getSemantics()) {
326 <<
"FloatAttr type doesn't match the type implied by its value";
335SymbolRefAttr SymbolRefAttr::get(
MLIRContext *ctx, StringRef value,
337 return get(StringAttr::get(ctx, value), nestedRefs);
341 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
345 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
351 assert(symName &&
"value does not have a valid symbol name");
352 return SymbolRefAttr::get(symName);
355StringAttr SymbolRefAttr::getLeafReference()
const {
356 ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
357 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
364int64_t IntegerAttr::getInt()
const {
366 "must be signless integer");
367 return getValue().getSExtValue();
370int64_t IntegerAttr::getSInt()
const {
371 assert(
getType().isSignedInteger() &&
"must be signed integer");
372 return getValue().getSExtValue();
375uint64_t IntegerAttr::getUInt()
const {
376 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
377 return getValue().getZExtValue();
382APSInt IntegerAttr::getAPSInt()
const {
383 assert(!
getType().isSignlessInteger() &&
384 "Signless integers don't carry a sign for APSInt");
385 return APSInt(getValue(),
getType().isUnsignedInteger());
389 Type type, APInt value) {
390 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
391 if (integerType.getWidth() != value.getBitWidth())
392 return emitError() <<
"integer type bit width (" << integerType.getWidth()
393 <<
") doesn't match value bit width ("
394 << value.getBitWidth() <<
")";
397 if (llvm::isa<IndexType>(type)) {
398 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
400 <<
"value bit width (" << value.getBitWidth()
401 <<
") doesn't match index type internal storage bit width ("
402 << IndexType::kInternalStorageBitWidth <<
")";
405 return emitError() <<
"expected integer or index type";
408BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
409 auto attr = Base::get(type.getContext(), type, APInt(1, value));
410 return llvm::cast<BoolAttr>(attr);
418 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
419 return storage->value.getBoolValue();
423 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
424 return intAttr && intAttr.getType().isSignlessInteger(1);
432 StringAttr dialect, StringRef attrData,
435 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
442 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
443 <<
" attribute created with unregistered dialect. If this is "
444 "intended, please call allowUnregisteredDialects() on the "
445 "MLIRContext, or use -allow-unregistered-dialect with "
446 "the MLIR opt tool used";
459 return llvm::alignTo<8>(origWidth);
469 assert(llvm::endianness::native == llvm::endianness::big);
470 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
475 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
476 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
481 size_t lastWordPos = numFilledWords;
483 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
484 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
485 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
489 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
490 valueLE.begin(),
result + lastWordPos,
491 (numBytes - lastWordPos) * CHAR_BIT, 1);
498 assert(llvm::endianness::native == llvm::endianness::big);
499 assert(
result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
506 size_t numFilledWords = (
result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
508 inArray, numFilledWords,
509 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())));
514 size_t lastWordPos = numFilledWords;
516 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
517 inArray + lastWordPos, inArrayLE.begin(),
518 (numBytes - lastWordPos) * CHAR_BIT, 1);
522 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
524 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())) +
526 APInt::APINT_BITS_PER_WORD, 1);
530static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
531 size_t bitWidth = value.getBitWidth();
534 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
535 if (llvm::endianness::native == llvm::endianness::big) {
542 rawData + (bitPos / CHAR_BIT));
544 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
545 llvm::divideCeil(bitWidth, CHAR_BIT),
546 rawData + (bitPos / CHAR_BIT));
552static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
554 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
555 APInt
result(bitWidth, 0);
556 if (llvm::endianness::native == llvm::endianness::big) {
563 llvm::divideCeil(bitWidth, CHAR_BIT),
result);
565 std::copy_n(rawData + (bitPos / CHAR_BIT),
566 llvm::divideCeil(bitWidth, CHAR_BIT),
568 reinterpret_cast<const char *
>(
result.getRawData())));
575template <
typename Values>
577 return (values.size() == 1) ||
578 (type.getNumElements() ==
static_cast<int64_t>(values.size()));
589DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
591 : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
593 attr.getAsOpaquePointer(),
index) {}
597 Type eltTy = owner.getElementType();
598 if (llvm::dyn_cast<IntegerType>(eltTy))
600 if (llvm::isa<IndexType>(eltTy))
602 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
605 return FloatAttr::get(eltTy, *floatIt);
607 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
608 auto complexEltTy = complexTy.getElementType();
610 if (llvm::isa<IntegerType>(complexEltTy)) {
611 auto value = *complexIntIt;
612 auto real = IntegerAttr::get(complexEltTy, value.real());
613 auto imag = IntegerAttr::get(complexEltTy, value.imag());
614 return ArrayAttr::get(complexTy.getContext(),
619 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
620 auto value = *complexFloatIt;
621 auto real = FloatAttr::get(complexEltTy, value.real());
622 auto imag = FloatAttr::get(complexEltTy, value.imag());
623 return ArrayAttr::get(complexTy.getContext(),
626 if (llvm::isa<DenseStringElementsAttr>(owner)) {
628 return StringAttr::get(owner.isSplat() ? vals.front() : vals[
index], eltTy);
630 llvm_unreachable(
"unexpected element type");
637DenseElementsAttr::BoolElementIterator::BoolElementIterator(
650DenseElementsAttr::IntElementIterator::IntElementIterator(
666DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
672 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
692 return emitError() <<
"expected integer or floating point element type";
693 int64_t dataSize = rawData.size();
696 if (
size * elementSize != dataSize) {
697 return emitError() <<
"expected data size (" <<
size <<
" elements, "
699 <<
" bytes each) does not match: " << dataSize
708template <
size_t width,
709 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
710struct DenseArrayAttrIntUtil {
711 static bool checkElementType(
Type eltType) {
712 auto type = llvm::dyn_cast<IntegerType>(eltType);
713 if (!type || type.getWidth() != width)
715 return type.getSignedness() == signedness;
719 return IntegerType::get(ctx, width, signedness);
722 template <
typename T>
723 static void printElement(
raw_ostream &os, T value) {
727 template <
typename T>
728 static ParseResult parseElement(
AsmParser &parser, T &value) {
733struct DenseArrayAttrUtil;
738struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
739 static void printElement(raw_ostream &os,
bool value) {
740 os << (value ?
"true" :
"false");
747struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
748 static void printElement(raw_ostream &os, int8_t value) {
749 os << static_cast<int>(value);
753struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
755struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
757struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
761struct DenseArrayAttrUtil<float> {
762 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
763 static Type
getElementType(MLIRContext *ctx) {
return Float32Type::get(ctx); }
764 static void printElement(raw_ostream &os,
float value) { os << value; }
767 static ParseResult parseElement(AsmParser &parser,
float &value) {
778struct DenseArrayAttrUtil<double> {
779 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
780 static Type
getElementType(MLIRContext *ctx) {
return Float64Type::get(ctx); }
781 static void printElement(raw_ostream &os,
float value) { os << value; }
782 static ParseResult parseElement(AsmParser &parser,
double &value) {
795 llvm::interleaveComma(
asArrayRef(), os, [&](T value) {
796 DenseArrayAttrUtil<T>::printElement(os, value);
814 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
816 data.push_back(value);
841 assert((raw.size() %
sizeof(T)) == 0);
842 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
843 raw.size() /
sizeof(T));
850 Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
851 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
852 content.size() *
sizeof(T));
853 return llvm::cast<DenseArrayAttrImpl<T>>(
854 Base::get(context, elementType, content.size(), rawArray));
859 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
860 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
883 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
889 Type eltType = type.getElementType();
892 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
893 if (complexType.getElementType().isIntOrIndex()) {
895 complexValues.reserve(values.size());
897 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
898 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
899 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
900 auto attr0 = arrayAttr[0];
901 auto attr1 = arrayAttr[1];
902 complexValues.push_back(
903 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
904 llvm::cast<IntegerAttr>(attr1).getValue()));
910 complexValues.reserve(values.size());
912 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
913 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
914 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
915 auto attr0 = arrayAttr[0];
916 auto attr1 = arrayAttr[1];
917 complexValues.push_back(
918 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
919 llvm::cast<FloatAttr>(attr1).getValue()));
928 stringValues.reserve(values.size());
930 assert(llvm::isa<StringAttr>(attr) &&
931 "expected string value for non integer/index/float element");
932 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
934 return get(type, stringValues);
943 llvm::divideCeil(storageBitWidth * values.size(), CHAR_BIT));
945 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
946 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
947 assert(floatAttr.getType() == eltType &&
948 "expected float attribute type to equal element type");
949 intVal = floatAttr.getValue().bitcastToAPInt();
950 }
else if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(values[i])) {
951 assert(intAttr.getType() == eltType &&
952 "expected integer attribute type to equal element type");
953 intVal = intAttr.getValue();
959 assert(intVal.getBitWidth() == bitWidth &&
960 "expected value to have same bitwidth as element type");
961 writeBits(data.data(), i * storageBitWidth, intVal);
964 return DenseIntOrFPElementsAttr::getRaw(type, data);
970 assert(type.getElementType().isInteger(1));
971 return DenseIntOrFPElementsAttr::getRaw(
972 type,
ArrayRef<char>(
reinterpret_cast<const char *
>(values.data()),
978 assert(!type.getElementType().isIntOrFloat());
979 return DenseStringElementsAttr::get(type, values);
987 assert(type.getElementType().isIntOrIndex());
990 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
993 ArrayRef<std::complex<APInt>> values) {
994 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
995 assert(llvm::isa<IntegerType>(
complex.getElementType()));
998 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1000 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1008 assert(llvm::isa<FloatType>(type.getElementType()));
1011 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1015 ArrayRef<std::complex<APFloat>> values) {
1016 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
1017 assert(llvm::isa<FloatType>(
complex.getElementType()));
1022 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1030 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1037 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1038 int64_t numElements = type.getNumElements();
1042 return rawBufferWidth == storageWidth ||
1043 rawBufferWidth == storageWidth * numElements;
1053 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1054 if (denseEltBitWidth != dataSize) {
1055 LDBG() <<
"expected dense element bit width " << denseEltBitWidth
1056 <<
" to match data size " << dataSize <<
" for type " << type;
1062 bool valid = llvm::isa<FloatType>(type);
1064 LDBG() <<
"expected float type when isInt is false, but found " << type;
1070 auto intType = llvm::dyn_cast<IntegerType>(type);
1072 LDBG() <<
"expected integer type when isInt is true, but found " << type;
1077 if (intType.isSignless())
1080 bool valid = intType.isSigned() == isSigned;
1082 LDBG() <<
"expected signedness " << isSigned <<
" to match type " << type;
1090 bool isInt,
bool isSigned) {
1091 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1099 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1104 bool isSigned)
const {
1105 return ::isValidIntOrFloat(
getElementType(), dataEltSize, isInt, isSigned);
1108 bool isSigned)
const {
1109 return ::isValidIntOrFloat(
1111 dataEltSize / 2, isInt, isSigned);
1118 if (isa<DenseStringElementsAttr>(*
this))
1121 size_t storageSize = llvm::divideCeil(
1128 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1145 const auto &elementSemantics = eltTy.getFloatSemantics();
1156 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1159 const auto &semantics = eltTy.getFloatSemantics();
1161 getType(), {semantics, {*
this, 0}},
1178 ShapedType curType =
getType();
1179 if (curType == newType)
1182 assert(newType.getElementType() == curType.getElementType() &&
1183 "expected the same element type");
1184 assert(newType.getNumElements() == curType.getNumElements() &&
1185 "expected the same number of elements");
1186 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1190 assert(
isSplat() &&
"expected a splat type");
1192 ShapedType curType =
getType();
1193 if (curType == newType)
1196 assert(newType.getElementType() == curType.getElementType() &&
1197 "expected the same element type");
1198 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1206 ShapedType curType =
getType();
1207 Type curElType = curType.getElementType();
1208 if (curElType == newElType)
1213 "expected element types with the same bitwidth");
1214 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1221 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1227 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1236 return getType().getElementType();
1240 return getType().getNumElements();
1248template <
typename APRangeT>
1251 APRangeT &&values) {
1252 size_t numValues = llvm::size(values);
1253 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1255 for (
auto it = values.begin(), e = values.end(); it != e;
1256 ++it, offset += storageWidth) {
1257 assert((*it).getBitWidth() <= storageWidth);
1265DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1266 size_t storageWidth,
1267 ArrayRef<APFloat> values) {
1268 SmallVector<char> data;
1269 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1271 return DenseIntOrFPElementsAttr::getRaw(type, data);
1277DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1278 size_t storageWidth,
1279 ArrayRef<APInt> values) {
1280 SmallVector<char> data;
1282 return DenseIntOrFPElementsAttr::getRaw(type, data);
1285DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1286 ArrayRef<char> data) {
1287 assert(type.hasStaticShape() &&
"type must have static shape");
1288 assert(isValidRawBuffer(type, data));
1289 return Base::get(type.getContext(), type, data);
1295DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1296 ArrayRef<char> data,
1297 int64_t dataEltSize,
1301 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1302 dataEltSize / 2, isInt, isSigned) &&
1303 "Try re-running with -debug-only=builtinattributes");
1305 int64_t numElements = data.size() / dataEltSize;
1307 assert(numElements == 1 || numElements == type.getNumElements());
1308 return getRaw(type, data);
1315DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1316 int64_t dataEltSize,
bool isInt,
1320 "Try re-running with -debug-only=builtinattributes");
1322 int64_t numElements = data.size() / dataEltSize;
1323 assert(numElements == 1 || numElements == type.getNumElements());
1325 return getRaw(type, data);
1328void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1329 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1330 size_t numElements) {
1331 using llvm::support::ulittle16_t;
1332 using llvm::support::ulittle32_t;
1333 using llvm::support::ulittle64_t;
1335 assert(llvm::endianness::native == llvm::endianness::big);
1339 switch (elementBitWidth) {
1341 const ulittle16_t *inRawDataPos =
1342 reinterpret_cast<const ulittle16_t *
>(inRawData);
1343 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1344 std::copy_n(inRawDataPos, numElements, outDataPos);
1348 const ulittle32_t *inRawDataPos =
1349 reinterpret_cast<const ulittle32_t *
>(inRawData);
1350 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1351 std::copy_n(inRawDataPos, numElements, outDataPos);
1355 const ulittle64_t *inRawDataPos =
1356 reinterpret_cast<const ulittle64_t *
>(inRawData);
1357 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1358 std::copy_n(inRawDataPos, numElements, outDataPos);
1362 size_t nBytes = elementBitWidth / CHAR_BIT;
1363 for (
size_t i = 0; i < nBytes; i++)
1364 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1370void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1371 ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1373 size_t numElements = type.getNumElements();
1374 Type elementType = type.getElementType();
1375 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1376 elementType = complexTy.getElementType();
1377 numElements = numElements * 2;
1380 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1381 inRawData.size() <= outRawData.size());
1382 if (elementBitWidth <= CHAR_BIT)
1383 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1385 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1386 elementBitWidth, numElements);
1393template <
typename Fn,
typename Attr>
1395 Type newElementType,
1400 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1402 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1403 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1406 auto processElt = [&](
decltype(*attr.begin()) value,
size_t index) {
1407 auto newInt = mapping(value);
1408 assert(newInt.getBitWidth() == bitWidth);
1413 if (attr.isSplat()) {
1414 processElt(*attr.begin(), 0);
1415 return newArrayType;
1419 uint64_t elementIdx = 0;
1420 for (
auto value : attr)
1421 processElt(value, elementIdx++);
1422 return newArrayType;
1431 return getRaw(newArrayType, elementData);
1436 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1437 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1450 return getRaw(newArrayType, elementData);
1455 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1456 return denseAttr.getType().getElementType().isIntOrIndex();
1464DenseResourceElementsAttr
1465DenseResourceElementsAttr::get(ShapedType type,
1467 return Base::get(type.getContext(), type, handle);
1470DenseResourceElementsAttr DenseResourceElementsAttr::get(ShapedType type,
1477 return get(type, manager.insert(blobName, std::move(blob)));
1480ArrayRef<char> DenseResourceElementsAttr::getData() {
1481 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1482 return blob->getDataAs<
char>();
1493template <
typename T>
1494struct DenseResourceAttrUtil;
1495template <
size_t w
idth,
bool isSigned>
1496struct DenseResourceElementsAttrIntUtil {
1497 static bool checkElementType(Type eltType) {
1498 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1499 if (!type || type.getWidth() != width)
1501 return isSigned ? !type.isUnsigned() : !type.isSigned();
1505struct DenseResourceAttrUtil<bool> {
1506 static bool checkElementType(Type eltType) {
1511struct DenseResourceAttrUtil<int8_t>
1512 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1514struct DenseResourceAttrUtil<uint8_t>
1515 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1517struct DenseResourceAttrUtil<int16_t>
1518 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1520struct DenseResourceAttrUtil<uint16_t>
1521 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1523struct DenseResourceAttrUtil<int32_t>
1524 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1526struct DenseResourceAttrUtil<uint32_t>
1527 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1529struct DenseResourceAttrUtil<int64_t>
1530 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1532struct DenseResourceAttrUtil<uint64_t>
1533 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1535struct DenseResourceAttrUtil<float> {
1536 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
1539struct DenseResourceAttrUtil<double> {
1540 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
1544template <
typename T>
1545DenseResourceElementsAttrBase<T>
1550 "alignment mismatch between expected alignment and blob alignment");
1551 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1552 "size mismatch between expected element width and blob size");
1553 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1554 "invalid shape element type for provided type `T`");
1555 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1556 DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1559template <
typename T>
1560std::optional<ArrayRef<T>>
1563 return blob->template getDataAs<T>();
1564 return std::nullopt;
1567template <
typename T>
1569 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1570 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1571 resourceAttr.getElementType());
1596APFloat SparseElementsAttr::getZeroAPFloat()
const {
1598 return APFloat(eltType.getFloatSemantics());
1602APInt SparseElementsAttr::getZeroAPInt()
const {
1604 return APInt::getZero(eltType.getWidth());
1608Attribute SparseElementsAttr::getZeroAttr()
const {
1612 if (llvm::isa<FloatType>(eltType))
1613 return FloatAttr::get(eltType, 0);
1616 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1617 auto eltType = complexTy.getElementType();
1619 if (llvm::isa<FloatType>(eltType))
1620 zero = FloatAttr::get(eltType, 0);
1622 zero = IntegerAttr::get(eltType, 0);
1623 return ArrayAttr::get(complexTy.getContext(),
1624 ArrayRef<Attribute>{zero, zero});
1628 if (llvm::isa<DenseStringElementsAttr>(getValues()))
1629 return StringAttr::get(
"", eltType);
1632 return IntegerAttr::get(eltType, 0);
1637SmallVector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1638 SmallVector<ptrdiff_t> flatSparseIndices;
1643 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1644 if (sparseIndices.isSplat()) {
1646 *sparseIndexValues.begin());
1647 flatSparseIndices.push_back(getFlattenedIndex(
indices));
1648 return flatSparseIndices;
1652 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1653 size_t rank =
getType().getRank();
1654 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1655 flatSparseIndices.push_back(getFlattenedIndex(
1656 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1657 return flatSparseIndices;
1662 ShapedType type, DenseIntElementsAttr sparseIndices,
1663 DenseElementsAttr values) {
1664 ShapedType valuesType = values.
getType();
1665 if (valuesType.getRank() != 1)
1666 return emitError() <<
"expected 1-d tensor for sparse element values";
1669 ShapedType indicesType = sparseIndices.getType();
1670 auto emitShapeError = [&]() {
1671 return emitError() <<
"expected shape ([" << type.getShape()
1672 <<
"]); inferred shape of indices literal (["
1673 << indicesType.getShape()
1674 <<
"]); inferred shape of values literal (["
1675 << valuesType.getShape() <<
"])";
1678 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1679 if (indicesRank == 2) {
1680 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1681 return emitShapeError();
1682 }
else if (indicesRank != 1 || rank != 1) {
1683 return emitShapeError();
1686 int64_t numSparseIndices = indicesType.getDimSize(0);
1687 if (numSparseIndices != valuesType.getDimSize(0))
1688 return emitShapeError();
1691 auto emitIndexError = [&](
unsigned indexNum, ArrayRef<uint64_t> index) {
1693 <<
"sparse index #" << indexNum
1694 <<
" is not contained within the value shape, with index=[" << index
1695 <<
"], and type=" << type;
1699 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1700 if (sparseIndices.isSplat()) {
1701 SmallVector<uint64_t>
indices(rank, *sparseIndexValues.begin());
1702 if (!ElementsAttr::isValidIndex(type,
indices))
1703 return emitIndexError(0,
indices);
1708 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1709 ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1711 if (!ElementsAttr::isValidIndex(type, index))
1712 return emitIndexError(i, index);
1727 return getImpl()->referencedAttr;
1738 unsigned nSymbols = 0;
1742 if (ShapedType::isStatic(offset)) {
1752 for (
const auto &en : llvm::enumerate(strides)) {
1753 auto dim = en.index();
1754 auto stride = en.value();
1758 if (ShapedType::isStatic(stride))
1763 expr = expr + d * mult;
static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt, bool isSigned)
Check the information for a C++ data type, check if this type is valid for the current attribute.
static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes, char *result)
Copy actual numBytes data from value (APInt) to char array(result) for BE format.
static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, Type newElementType, llvm::SmallVectorImpl< char > &data)
static bool hasSameNumElementsOrSplat(ShapedType type, const Values &values)
Returns true if 'values' corresponds to a splat, i.e.
static void writeAPIntsToBuffer(size_t storageWidth, SmallVectorImpl< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
static void writeBits(char *rawData, size_t bitPos, APInt value)
Writes value to the bit position bitPos in array rawData.
static bool dictionaryAttrSort(ArrayRef< NamedAttribute > value, SmallVectorImpl< NamedAttribute > &storage)
Helper function that does either an in place sort or sorts from source array into destination.
static std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static size_t getDenseElementStorageWidth(size_t origWidth)
Get the bitwidth of a dense element type within the buffer.
static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes, APInt &result)
Copy numBytes data from inArray(char array) to result(APINT) for BE format.
static bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth)
Reads the next bitWidth bits from the bit position bitPos in array rawData.
static Type getElementType(Type type)
Determine the element type of type.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalRSquare()=0
Parse a ] token if present.
virtual ParseResult parseFloat(double &result)=0
Parse a floating point value from the stream.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
This class represents a processed binary blob of data.
size_t getDataAlignment() const
Return the alignment of the underlying data.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Attributes are known-constant values of operations.
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
MLIRContext * getContext() const
Return the context this attribute belongs to.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static bool classof(Attribute attr)
Methods for support type inquiry through isa, cast, and dyn_cast.
constexpr Attribute()=default
bool getValue() const
Return the boolean value of this attribute.
Attribute operator*() const
Accesses the Attribute value at this iterator position.
A utility iterator that allows walking over the internal bool values.
bool operator*() const
Accesses the bool value at this iterator position.
Iterator for walking over complex APFloat values.
A utility iterator that allows walking over the internal raw complex APInt values.
std::complex< APInt > operator*() const
Accesses the raw std::complex<APInt> value at this iterator position.
Iterator for walking over APFloat values.
A utility iterator that allows walking over the internal raw APInt values.
APInt operator*() const
Accesses the raw APInt value at this iterator position.
An attribute that represents a reference to a dense vector or tensor object.
ArrayRef< StringRef > getRawStringData() const
Return the raw StringRef data held by this attribute.
IntElementIterator raw_int_begin() const
Iterators to various elements that require out-of-line definition.
static DenseElementsAttr getRawIntOrFloat(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of integer or floating-point typ...
static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of complex type.
static bool classof(Attribute attr)
Method for support type inquiry through isa, cast and dyn_cast.
bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
detail::ElementsAttrRange< IteratorT > iterator_range_impl
The iterator range over the given iterator type T.
int64_t getNumElements() const
Returns the number of elements held by this attribute.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Returns true if the given buffer is a valid raw buffer for the given type.
int64_t size() const
Returns the number of elements held by this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
constexpr Attribute()=default
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each int value to a new underlying APInt.
Type getElementType() const
Return the element type of this DenseElementsAttr.
FailureOr< iterator_range_impl< ComplexFloatElementIterator > > tryGetComplexFloatValues() const
IntElementIterator raw_int_end() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
FailureOr< iterator_range_impl< FloatElementIterator > > tryGetFloatValues() const
DenseElementsAttr bitcast(Type newElType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has bitcast eleme...
bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
FailureOr< iterator_range_impl< ComplexIntElementIterator > > tryGetComplexIntValues() const
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APFloat &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
An attribute that associates a referenced attribute with a unique identifier.
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
Attribute getReferencedAttr() const
Returns the referenced attribute.
A symbol reference with a reference path containing a single element.
This class represents a diagnostic that is inflight and set to be reported.
MLIRContext is the top-level object for a collection of MLIR operations.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
NamedAttribute represents a combination of a name and an Attribute value.
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
static bool classof(Attribute attr)
Support for isa<>/cast<>.
ArrayRef< T > asArrayRef() const
void print(AsmPrinter &printer) const
Print the short form [42, 100, -1] without any type prefix.
static Attribute parse(AsmParser &parser, Type type)
Parse the short form [42, 100, -1] without any type prefix.
static Attribute parseWithoutBraces(AsmParser &parser, Type type)
Parse the short form 42, 100, -1 without any type prefix or braces.
void printWithoutBraces(raw_ostream &os) const
Print the short form 42, 100, -1 without any braces or type prefix.
Impl iterator for indexed DenseElementsAttr iterators that records a data pointer and data index that...
ptrdiff_t getDataIndex() const
const char * getData() const
Base class for DenseResourceElementsAttr that is instantiated and specialized for each supported elem...
static bool classof(Attribute attr)
Support for isa<>/cast<>.
static DenseResourceElementsAttrBase< T > get(ShapedType type, StringRef blobName, AsmResourceBlob blob)
A builder that inserts a new resource using the provided blob.
std::optional< ArrayRef< T > > tryGetAsArrayRef() const
Return the data of this attribute as an ArrayRef<T> if it is present, returns std::nullopt otherwise.
static ConcreteT get(MLIRContext *ctx, Args &&...args)
Get or create a new ConcreteT instance within the ctx.
ImplType * getImpl() const
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
DialectResourceBlobHandle< BuiltinDialect > DenseResourceElementsHandle
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
AffineMap makeStridedLinearLayoutMap(ArrayRef< int64_t > strides, int64_t offset, MLIRContext *context)
Given a list of strides (in which ShapedType::kDynamic represents a dynamic value),...
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
llvm::function_ref< Fn > function_ref
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object containing strings.