20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/Sequence.h"
22 #include "llvm/ADT/TypeSwitch.h"
23 #include "llvm/Support/Endian.h"
33 #define GET_ATTRDEF_CLASSES
34 #include "mlir/IR/BuiltinAttributes.cpp.inc"
40 void BuiltinDialect::registerAttributes() {
42 #define GET_ATTRDEF_LIST
43 #include "mlir/IR/BuiltinAttributes.cpp.inc"
55 template <
bool inPlace>
59 switch (value.size()) {
68 storage.assign({value[0]});
71 bool isSorted = value[0] < value[1];
74 std::swap(storage[0], storage[1]);
75 }
else if (isSorted) {
76 storage.assign({value[0], value[1]});
78 storage.assign({value[1], value[0]});
84 storage.assign(value.begin(), value.end());
86 bool isSorted = llvm::is_sorted(value);
89 llvm::array_pod_sort(storage.begin(), storage.end());
97 static std::optional<NamedAttribute>
99 const std::optional<NamedAttribute> none{std::nullopt};
100 if (value.size() < 2)
103 if (value.size() == 2)
104 return value[0].getName() == value[1].getName() ? value[0] : none;
106 const auto *it = std::adjacent_find(value.begin(), value.end(),
108 return l.getName() == r.getName();
110 return it != value.end() ? *it : none;
117 "DictionaryAttr element names must be unique");
124 "DictionaryAttr element names must be unique");
128 std::optional<NamedAttribute>
139 return DictionaryAttr::getEmpty(context);
143 if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
146 "DictionaryAttr element names must be unique");
151 DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
154 return DictionaryAttr::getEmpty(context);
156 assert(llvm::is_sorted(
158 "expected attribute values to be sorted");
160 "DictionaryAttr element names must be unique");
167 return it.second ? it.first->getValue() :
Attribute();
171 return it.second ? it.first->getValue() :
Attribute();
175 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
177 return it.second ? *it.first : std::optional<NamedAttribute>();
179 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
181 return it.second ? *it.first : std::optional<NamedAttribute>();
192 DictionaryAttr::iterator DictionaryAttr::begin()
const {
193 return getValue().begin();
195 DictionaryAttr::iterator DictionaryAttr::end()
const {
196 return getValue().end();
198 size_t DictionaryAttr::size()
const {
return getValue().size(); }
200 DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
210 auto printIntOrQuestion = [&](int64_t value) {
211 if (ShapedType::isDynamic(value))
218 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
221 if (getOffset() != 0) {
223 printIntOrQuestion(getOffset());
229 AffineMap StridedLayoutAttr::getAffineMap()
const {
237 if (llvm::any_of(strides, [&](int64_t stride) {
return stride == 0; }))
238 return emitError() <<
"strides must not be zero";
247 if (shape.size() != getStrides().size())
248 return emitError() <<
"expected the number of strides to match the rank";
257 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
264 if (twine.isTriviallyEmpty())
276 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
278 Type StringAttr::getType()
const {
return getImpl()->type; }
280 Dialect *StringAttr::getReferencedDialect()
const {
281 return getImpl()->referencedDialect;
288 double FloatAttr::getValueAsDouble()
const {
289 return getValueAsDouble(getValue());
291 double FloatAttr::getValueAsDouble(APFloat value) {
292 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
293 bool losesInfo =
false;
294 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
297 return value.convertToDouble();
301 Type type, APFloat value) {
303 if (!llvm::isa<FloatType>(type))
304 return emitError() <<
"expected floating point type";
307 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
308 &value.getSemantics()) {
310 <<
"FloatAttr type doesn't match the type implied by its value";
325 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
329 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
335 assert(symName &&
"value does not have a valid symbol name");
339 StringAttr SymbolRefAttr::getLeafReference()
const {
341 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
348 int64_t IntegerAttr::getInt()
const {
349 assert((getType().isIndex() || getType().isSignlessInteger()) &&
350 "must be signless integer");
351 return getValue().getSExtValue();
354 int64_t IntegerAttr::getSInt()
const {
355 assert(getType().isSignedInteger() &&
"must be signed integer");
356 return getValue().getSExtValue();
359 uint64_t IntegerAttr::getUInt()
const {
360 assert(getType().isUnsignedInteger() &&
"must be unsigned integer");
361 return getValue().getZExtValue();
366 APSInt IntegerAttr::getAPSInt()
const {
367 assert(!getType().isSignlessInteger() &&
368 "Signless integers don't carry a sign for APSInt");
369 return APSInt(getValue(), getType().isUnsignedInteger());
373 Type type, APInt value) {
374 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
375 if (integerType.getWidth() != value.getBitWidth())
376 return emitError() <<
"integer type bit width (" << integerType.getWidth()
377 <<
") doesn't match value bit width ("
378 << value.getBitWidth() <<
")";
381 if (llvm::isa<IndexType>(type)) {
382 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
384 <<
"value bit width (" << value.getBitWidth()
385 <<
") doesn't match index type internal storage bit width ("
386 << IndexType::kInternalStorageBitWidth <<
")";
389 return emitError() <<
"expected integer or index type";
392 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
393 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
394 return llvm::cast<BoolAttr>(attr);
402 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
403 return storage->value.getBoolValue();
407 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
408 return intAttr && intAttr.getType().isSignlessInteger(1);
416 StringAttr dialect, StringRef attrData,
419 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
426 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
427 <<
" attribute created with unregistered dialect. If this is "
428 "intended, please call allowUnregisteredDialects() on the "
429 "MLIRContext, or use -allow-unregistered-dialect with "
430 "the MLIR opt tool used";
443 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
450 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
452 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
454 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
458 static bool getBit(
const char *rawData,
size_t bitPos) {
459 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
466 assert(llvm::support::endian::system_endianness() ==
467 llvm::support::endianness::big);
468 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
473 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
474 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
475 numFilledWords, result);
479 size_t lastWordPos = numFilledWords;
481 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
482 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
483 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
487 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
488 valueLE.begin(), result + lastWordPos,
489 (numBytes - lastWordPos) * CHAR_BIT, 1);
496 assert(llvm::support::endian::system_endianness() ==
497 llvm::support::endianness::big);
498 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
505 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
507 inArray, numFilledWords,
508 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
513 size_t lastWordPos = numFilledWords;
515 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
516 inArray + lastWordPos, inArrayLE.begin(),
517 (numBytes - lastWordPos) * CHAR_BIT, 1);
521 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
523 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
525 APInt::APINT_BITS_PER_WORD, 1);
529 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
530 size_t bitWidth = value.getBitWidth();
534 return setBit(rawData, bitPos, value.isOne());
537 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
538 if (llvm::support::endian::system_endianness() ==
539 llvm::support::endianness::big) {
546 rawData + (bitPos / CHAR_BIT));
548 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
549 llvm::divideCeil(bitWidth, CHAR_BIT),
550 rawData + (bitPos / CHAR_BIT));
556 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
559 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
562 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
563 APInt result(bitWidth, 0);
564 if (llvm::support::endian::system_endianness() ==
565 llvm::support::endianness::big) {
572 llvm::divideCeil(bitWidth, CHAR_BIT), result);
574 std::copy_n(rawData + (bitPos / CHAR_BIT),
575 llvm::divideCeil(bitWidth, CHAR_BIT),
577 reinterpret_cast<const char *
>(result.getRawData())));
584 template <
typename Values>
586 return (values.size() == 1) ||
587 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
597 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
599 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
601 attr.getAsOpaquePointer(), index) {}
605 Type eltTy = owner.getElementType();
606 if (
auto intEltTy = llvm::dyn_cast<IntegerType>(eltTy))
608 if (llvm::isa<IndexType>(eltTy))
610 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
615 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
616 auto complexEltTy = complexTy.getElementType();
618 if (llvm::isa<IntegerType>(complexEltTy)) {
619 auto value = *complexIntIt;
627 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
628 auto value = *complexFloatIt;
634 if (llvm::isa<DenseStringElementsAttr>(owner)) {
636 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
638 llvm_unreachable(
"unexpected element type");
644 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
650 return getBit(getData(), getDataIndex());
656 DenseElementsAttr::IntElementIterator::IntElementIterator(
671 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
674 std::complex<APInt>, std::complex<APInt>,
675 std::complex<APInt>>(
677 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
684 size_t offset = getDataIndex() * storageWidth * 2;
685 return {
readBits(getData(), offset, bitWidth),
686 readBits(getData(), offset + storageWidth, bitWidth)};
697 return emitError() <<
"expected integer or floating point element type";
698 int64_t dataSize = rawData.size();
699 int64_t elementSize =
701 if (
size * elementSize != dataSize) {
702 return emitError() <<
"expected data size (" <<
size <<
" elements, "
704 <<
" bytes each) does not match: " << dataSize
713 template <
size_t width,
714 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
715 struct DenseArrayAttrIntUtil {
716 static bool checkElementType(
Type eltType) {
717 auto type = llvm::dyn_cast<IntegerType>(eltType);
718 if (!type || type.getWidth() != width)
720 return type.getSignedness() == signedness;
727 template <
typename T>
728 static void printElement(raw_ostream &os, T value) {
732 template <
typename T>
737 template <
typename T>
738 struct DenseArrayAttrUtil;
743 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
744 static void printElement(raw_ostream &os,
bool value) {
745 os << (value ?
"true" :
"false");
752 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
753 static void printElement(raw_ostream &os, int8_t value) {
754 os << static_cast<int>(value);
758 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
760 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
762 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
766 struct DenseArrayAttrUtil<float> {
767 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
769 static void printElement(raw_ostream &os,
float value) { os << value; }
783 struct DenseArrayAttrUtil<double> {
784 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
786 static void printElement(raw_ostream &os,
float value) { os << value; }
793 template <
typename T>
798 template <
typename T>
800 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
801 DenseArrayAttrUtil<T>::printElement(os, value);
805 template <
typename T>
808 printWithoutBraces(os);
813 template <
typename T>
819 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
821 data.push_back(value);
829 template <
typename T>
836 Attribute result = parseWithoutBraces(parser, odsType);
843 template <
typename T>
846 assert((raw.size() %
sizeof(T)) == 0);
847 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
848 raw.size() /
sizeof(T));
852 template <
typename T>
856 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
857 content.size() *
sizeof(T));
858 return llvm::cast<DenseArrayAttrImpl<T>>(
859 Base::get(context, elementType, content.size(), rawArray));
862 template <
typename T>
864 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
865 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
888 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
895 Type eltType = type.getElementType();
898 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
899 if (complexType.getElementType().isIntOrIndex()) {
901 complexValues.reserve(values.size());
903 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
904 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
905 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
906 auto attr0 = arrayAttr[0];
907 auto attr1 = arrayAttr[1];
908 complexValues.push_back(
909 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
910 llvm::cast<IntegerAttr>(attr1).getValue()));
916 complexValues.reserve(values.size());
918 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
919 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
920 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
921 auto attr0 = arrayAttr[0];
922 auto attr1 = arrayAttr[1];
923 complexValues.push_back(
924 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
925 llvm::cast<FloatAttr>(attr1).getValue()));
934 stringValues.reserve(values.size());
936 assert(llvm::isa<StringAttr>(attr) &&
937 "expected string value for non integer/index/float element");
938 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
940 return get(type, stringValues);
949 llvm::divideCeil(storageBitWidth * values.size(), CHAR_BIT));
951 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
952 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
953 assert(floatAttr.getType() == eltType &&
954 "expected float attribute type to equal element type");
955 intVal = floatAttr.getValue().bitcastToAPInt();
957 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
958 assert(intAttr.getType() == eltType &&
959 "expected integer attribute type to equal element type");
960 intVal = intAttr.getValue();
963 assert(intVal.getBitWidth() == bitWidth &&
964 "expected value to have same bitwidth as element type");
965 writeBits(data.data(), i * storageBitWidth, intVal);
969 if (values.size() == 1 && eltType.
isInteger(1))
970 data[0] = data[0] ? -1 : 0;
972 return DenseIntOrFPElementsAttr::getRaw(type, data);
978 assert(type.getElementType().isInteger(1));
980 std::vector<char> buff(llvm::divideCeil(values.size(), CHAR_BIT));
982 if (!values.empty()) {
984 bool firstValue = values[0];
985 for (
int i = 0, e = values.size(); i != e; ++i) {
986 isSplat &= values[i] == firstValue;
987 setBit(buff.data(), i, values[i]);
993 buff[0] = values[0] ? -1 : 0;
997 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1002 assert(!type.getElementType().isIntOrFloat());
1011 assert(type.getElementType().isIntOrIndex());
1014 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1017 ArrayRef<std::complex<APInt>> values) {
1018 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1019 assert(llvm::isa<IntegerType>(complex.getElementType()));
1022 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1024 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1032 assert(llvm::isa<FloatType>(type.getElementType()));
1035 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1039 ArrayRef<std::complex<APFloat>> values) {
1040 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1041 assert(llvm::isa<FloatType>(complex.getElementType()));
1046 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1054 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1060 bool &detectedSplat) {
1062 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1063 int64_t numElements = type.getNumElements();
1066 detectedSplat = numElements == 1;
1069 if (storageWidth == 1) {
1072 if (rawBuffer.size() == 1) {
1073 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1074 if (rawByte == 0 || rawByte == 0xff) {
1075 detectedSplat =
true;
1081 return rawBufferWidth == llvm::alignTo<8>(numElements);
1086 if (rawBufferWidth == storageWidth) {
1087 detectedSplat =
true;
1092 return rawBufferWidth == storageWidth * numElements;
1102 static_cast<size_t>(dataEltSize * CHAR_BIT))
1107 return llvm::isa<FloatType>(type);
1111 auto intType = llvm::dyn_cast<IntegerType>(type);
1116 if (intType.isSignless())
1118 return intType.isSigned() ? isSigned : !isSigned;
1124 int64_t dataEltSize,
1125 bool isInt,
bool isSigned) {
1126 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1131 int64_t dataEltSize,
1134 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1139 bool isSigned)
const {
1143 bool isSigned)
const {
1146 dataEltSize / 2, isInt, isSigned);
1157 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1174 const auto &elementSemantics = eltTy.getFloatSemantics();
1185 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1188 const auto &semantics = eltTy.getFloatSemantics();
1190 getType(), {semantics, {*
this, 0}},
1207 ShapedType curType =
getType();
1208 if (curType == newType)
1211 assert(newType.getElementType() == curType.getElementType() &&
1212 "expected the same element type");
1213 assert(newType.getNumElements() == curType.getNumElements() &&
1214 "expected the same number of elements");
1215 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1219 assert(
isSplat() &&
"expected a splat type");
1221 ShapedType curType =
getType();
1222 if (curType == newType)
1225 assert(newType.getElementType() == curType.getElementType() &&
1226 "expected the same element type");
1227 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1235 ShapedType curType =
getType();
1236 Type curElType = curType.getElementType();
1237 if (curElType == newElType)
1242 "expected element types with the same bitwidth");
1243 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1250 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType, mapping);
1255 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType, mapping);
1263 return getType().getElementType();
1267 return getType().getNumElements();
1275 template <
typename APRangeT>
1277 APRangeT &&values) {
1278 size_t numValues = llvm::size(values);
1279 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1281 for (
auto it = values.begin(), e = values.end(); it != e;
1282 ++it, offset += storageWidth) {
1283 assert((*it).getBitWidth() <= storageWidth);
1288 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1289 data[0] = data[0] ? -1 : 0;
1296 size_t storageWidth,
1298 std::vector<char> data;
1299 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1301 return DenseIntOrFPElementsAttr::getRaw(type, data);
1308 size_t storageWidth,
1310 std::vector<char> data;
1312 return DenseIntOrFPElementsAttr::getRaw(type, data);
1317 assert(type.hasStaticShape() &&
"type must have static shape");
1330 int64_t dataEltSize,
1334 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1335 dataEltSize / 2, isInt, isSigned));
1337 int64_t numElements = data.size() / dataEltSize;
1339 assert(numElements == 1 || numElements == type.getNumElements());
1340 return getRaw(type, data);
1347 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1348 int64_t dataEltSize,
bool isInt,
1353 int64_t numElements = data.size() / dataEltSize;
1354 assert(numElements == 1 || numElements == type.getNumElements());
1356 return getRaw(type, data);
1359 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1360 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1361 size_t numElements) {
1362 using llvm::support::ulittle16_t;
1363 using llvm::support::ulittle32_t;
1364 using llvm::support::ulittle64_t;
1366 assert(llvm::support::endian::system_endianness() ==
1367 llvm::support::endianness::big);
1371 switch (elementBitWidth) {
1373 const ulittle16_t *inRawDataPos =
1374 reinterpret_cast<const ulittle16_t *
>(inRawData);
1375 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1376 std::copy_n(inRawDataPos, numElements, outDataPos);
1380 const ulittle32_t *inRawDataPos =
1381 reinterpret_cast<const ulittle32_t *
>(inRawData);
1382 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1383 std::copy_n(inRawDataPos, numElements, outDataPos);
1387 const ulittle64_t *inRawDataPos =
1388 reinterpret_cast<const ulittle64_t *
>(inRawData);
1389 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1390 std::copy_n(inRawDataPos, numElements, outDataPos);
1394 size_t nBytes = elementBitWidth / CHAR_BIT;
1395 for (
size_t i = 0; i < nBytes; i++)
1396 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1402 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1405 size_t numElements = type.getNumElements();
1406 Type elementType = type.getElementType();
1407 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1408 elementType = complexTy.getElementType();
1409 numElements = numElements * 2;
1412 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1413 inRawData.size() <= outRawData.size());
1414 if (elementBitWidth <= CHAR_BIT)
1415 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1417 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1418 elementBitWidth, numElements);
1425 template <
typename Fn,
typename Attr>
1427 Type newElementType,
1432 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1434 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1435 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1438 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1439 auto newInt = mapping(value);
1440 assert(newInt.getBitWidth() == bitWidth);
1441 writeBits(data.data(), index * storageBitWidth, newInt);
1445 if (attr.isSplat()) {
1446 if (bitWidth == 1) {
1448 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1450 processElt(*attr.begin(), 0);
1452 return newArrayType;
1456 uint64_t elementIdx = 0;
1457 for (
auto value : attr)
1458 processElt(value, elementIdx++);
1459 return newArrayType;
1468 return getRaw(newArrayType, elementData);
1473 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1474 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1487 return getRaw(newArrayType, elementData);
1492 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1493 return denseAttr.getType().getElementType().isIntOrIndex();
1504 return Base::get(type.getContext(), type, handle);
1514 return get(type, manager.insert(blobName, std::move(blob)));
1523 template <
typename T>
1524 struct DenseResourceAttrUtil;
1525 template <
size_t w
idth,
bool isSigned>
1526 struct DenseResourceElementsAttrIntUtil {
1527 static bool checkElementType(
Type eltType) {
1528 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1529 if (!type || type.getWidth() != width)
1531 return isSigned ? !type.isUnsigned() : !type.isSigned();
1535 struct DenseResourceAttrUtil<bool> {
1536 static bool checkElementType(
Type eltType) {
1541 struct DenseResourceAttrUtil<int8_t>
1542 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1544 struct DenseResourceAttrUtil<uint8_t>
1545 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1547 struct DenseResourceAttrUtil<int16_t>
1548 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1550 struct DenseResourceAttrUtil<uint16_t>
1551 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1553 struct DenseResourceAttrUtil<int32_t>
1554 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1556 struct DenseResourceAttrUtil<uint32_t>
1557 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1559 struct DenseResourceAttrUtil<int64_t>
1560 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1562 struct DenseResourceAttrUtil<uint64_t>
1563 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1565 struct DenseResourceAttrUtil<float> {
1566 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1569 struct DenseResourceAttrUtil<double> {
1570 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1574 template <
typename T>
1580 "alignment mismatch between expected alignment and blob alignment");
1581 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1582 "size mismatch between expected element width and blob size");
1583 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1584 "invalid shape element type for provided type `T`");
1585 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1589 template <
typename T>
1590 std::optional<ArrayRef<T>>
1593 return blob->template getDataAs<T>();
1594 return std::nullopt;
1597 template <
typename T>
1599 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1600 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1601 resourceAttr.getElementType());
1626 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1628 return APFloat(eltType.getFloatSemantics());
1632 APInt SparseElementsAttr::getZeroAPInt()
const {
1638 Attribute SparseElementsAttr::getZeroAttr()
const {
1642 if (llvm::isa<FloatType>(eltType))
1646 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1647 auto eltType = complexTy.getElementType();
1649 if (llvm::isa<FloatType>(eltType))
1658 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1667 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1668 std::vector<ptrdiff_t> flatSparseIndices;
1673 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1674 if (sparseIndices.isSplat()) {
1676 *sparseIndexValues.begin());
1677 flatSparseIndices.push_back(getFlattenedIndex(indices));
1678 return flatSparseIndices;
1682 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1683 size_t rank =
getType().getRank();
1684 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1685 flatSparseIndices.push_back(getFlattenedIndex(
1686 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1687 return flatSparseIndices;
1694 ShapedType valuesType = values.
getType();
1695 if (valuesType.getRank() != 1)
1696 return emitError() <<
"expected 1-d tensor for sparse element values";
1699 ShapedType indicesType = sparseIndices.getType();
1700 auto emitShapeError = [&]() {
1701 return emitError() <<
"expected shape ([" << type.getShape()
1702 <<
"]); inferred shape of indices literal (["
1703 << indicesType.getShape()
1704 <<
"]); inferred shape of values literal (["
1705 << valuesType.getShape() <<
"])";
1708 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1709 if (indicesRank == 2) {
1710 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1711 return emitShapeError();
1712 }
else if (indicesRank != 1 || rank != 1) {
1713 return emitShapeError();
1716 int64_t numSparseIndices = indicesType.getDimSize(0);
1717 if (numSparseIndices != valuesType.getDimSize(0))
1718 return emitShapeError();
1723 <<
"sparse index #" << indexNum
1724 <<
" is not contained within the value shape, with index=[" << index
1725 <<
"], and type=" << type;
1729 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1730 if (sparseIndices.isSplat()) {
1732 if (!ElementsAttr::isValidIndex(type, indices))
1733 return emitIndexError(0, indices);
1738 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1741 if (!ElementsAttr::isValidIndex(type, index))
1742 return emitIndexError(i, index);
1756 unsigned nSymbols = 0;
1760 if (!ShapedType::isDynamic(offset)) {
1771 auto dim = en.index();
1772 auto stride = en.value();
1773 assert(stride != 0 &&
"Invalid stride specification");
1777 if (!ShapedType::isDynamic(stride))
1782 expr = expr + d * mult;
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
static void writeAPIntsToBuffer(size_t storageWidth, std::vector< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
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 void setBit(char *rawData, size_t bitPos, bool value)
Set a bit to a specific value.
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 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 getBit(const char *rawData, size_t bitPos)
Return the value of the specified bit.
static bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static bool hasSameElementsOrSplat(ShapedType type, const Values &values)
Returns true if 'values' corresponds to a splat, i.e.
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 bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
Operation::operand_range getIndices(Operation *op)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
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.
The following classes enable support for parsing and printing resources within MLIR assembly formats.
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.
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.
bool getValue() const
Return the boolean value of this attribute.
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
auto getValues() const
Return the held element values as a range of the given type.
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
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.
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.
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
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool &detectedSplat)
Returns true if the given buffer is a valid raw buffer for the given type.
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...
An attribute that represents a reference to a dense integer vector or tensor object.
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.
This class provides support for representing a failure result, or a valid value of type T.
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)
This class represents success/failure for parsing-like operations that find it important to chain tog...
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...
bool isInteger(unsigned width) const
Return true if this is an integer type with the specified width.
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...
Impl iterator for indexed DenseElementsAttr iterators that records a data pointer and data index that...
Base class for DenseResourceElementsAttr that is instantiated and specialized for each supported elem...
This class provides iterator utilities for an ElementsAttr range.
Include the generated interface declarations.
Detect if any of the given parameter types has a sub-element handler.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
std::pair< IteratorT, bool > findAttrSorted(IteratorT first, IteratorT last, StringRef name)
Using llvm::lower_bound requires an extra string comparison to check whether the returned iterator po...
Fraction operator*(const Fraction &x, const Fraction &y)
This header declares functions that assit transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
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.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
This class defines a dialect specific handle to a resource blob.
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
Get the interface for the dialect that owns handles of this type.
This class represents an efficient way to signal success or failure.
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.