20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/Endian.h"
25 #define DEBUG_TYPE "builtinattributes"
34 #define GET_ATTRDEF_CLASSES
35 #include "mlir/IR/BuiltinAttributes.cpp.inc"
41 void BuiltinDialect::registerAttributes() {
43 #define GET_ATTRDEF_LIST
44 #include "mlir/IR/BuiltinAttributes.cpp.inc"
46 addAttributes<DistinctAttr>();
57 template <
bool inPlace>
61 switch (value.size()) {
70 storage.assign({value[0]});
73 bool isSorted = value[0] < value[1];
76 std::swap(storage[0], storage[1]);
77 }
else if (isSorted) {
78 storage.assign({value[0], value[1]});
80 storage.assign({value[1], value[0]});
86 storage.assign(value.begin(), value.end());
88 bool isSorted = llvm::is_sorted(value);
91 llvm::array_pod_sort(storage.begin(), storage.end());
99 static std::optional<NamedAttribute>
101 const std::optional<NamedAttribute> none{std::nullopt};
102 if (value.size() < 2)
105 if (value.size() == 2)
106 return value[0].getName() == value[1].getName() ? value[0] : none;
108 const auto *it = std::adjacent_find(value.begin(), value.end(),
110 return l.getName() == r.getName();
112 return it != value.end() ? *it : none;
119 "DictionaryAttr element names must be unique");
126 "DictionaryAttr element names must be unique");
130 std::optional<NamedAttribute>
141 return DictionaryAttr::getEmpty(context);
145 if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
148 "DictionaryAttr element names must be unique");
153 DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
156 return DictionaryAttr::getEmpty(context);
158 assert(llvm::is_sorted(
160 "expected attribute values to be sorted");
162 "DictionaryAttr element names must be unique");
169 return it.second ? it.first->getValue() :
Attribute();
173 return it.second ? it.first->getValue() :
Attribute();
177 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
179 return it.second ? *it.first : std::optional<NamedAttribute>();
181 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
183 return it.second ? *it.first : std::optional<NamedAttribute>();
194 DictionaryAttr::iterator DictionaryAttr::begin()
const {
195 return getValue().begin();
197 DictionaryAttr::iterator DictionaryAttr::end()
const {
198 return getValue().end();
200 size_t DictionaryAttr::size()
const {
return getValue().size(); }
202 DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
212 auto printIntOrQuestion = [&](int64_t value) {
213 if (ShapedType::isDynamic(value))
220 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
223 if (getOffset() != 0) {
225 printIntOrQuestion(getOffset());
232 bool StridedLayoutAttr::hasStaticLayout()
const {
233 return ShapedType::isStatic(getOffset()) &&
234 ShapedType::isStaticShape(getStrides());
238 AffineMap StridedLayoutAttr::getAffineMap()
const {
250 LogicalResult StridedLayoutAttr::verifyLayout(
253 if (shape.size() != getStrides().size())
254 return emitError() <<
"expected the number of strides to match the rank";
262 int64_t &offset)
const {
263 llvm::append_range(strides, getStrides());
264 offset = getOffset();
272 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
279 if (twine.isTriviallyEmpty())
291 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
295 Dialect *StringAttr::getReferencedDialect()
const {
296 return getImpl()->referencedDialect;
303 double FloatAttr::getValueAsDouble()
const {
304 return getValueAsDouble(getValue());
306 double FloatAttr::getValueAsDouble(APFloat value) {
307 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
308 bool losesInfo =
false;
309 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
312 return value.convertToDouble();
316 Type type, APFloat value) {
318 if (!llvm::isa<FloatType>(type))
319 return emitError() <<
"expected floating point type";
322 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
323 &value.getSemantics()) {
325 <<
"FloatAttr type doesn't match the type implied by its value";
340 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
344 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
350 assert(symName &&
"value does not have a valid symbol name");
354 StringAttr SymbolRefAttr::getLeafReference()
const {
356 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
363 int64_t IntegerAttr::getInt()
const {
365 "must be signless integer");
366 return getValue().getSExtValue();
369 int64_t IntegerAttr::getSInt()
const {
370 assert(
getType().isSignedInteger() &&
"must be signed integer");
371 return getValue().getSExtValue();
374 uint64_t IntegerAttr::getUInt()
const {
375 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
376 return getValue().getZExtValue();
381 APSInt IntegerAttr::getAPSInt()
const {
382 assert(!
getType().isSignlessInteger() &&
383 "Signless integers don't carry a sign for APSInt");
384 return APSInt(getValue(),
getType().isUnsignedInteger());
388 Type type, APInt value) {
389 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
390 if (integerType.getWidth() != value.getBitWidth())
391 return emitError() <<
"integer type bit width (" << integerType.getWidth()
392 <<
") doesn't match value bit width ("
393 << value.getBitWidth() <<
")";
396 if (llvm::isa<IndexType>(type)) {
397 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
399 <<
"value bit width (" << value.getBitWidth()
400 <<
") doesn't match index type internal storage bit width ("
401 << IndexType::kInternalStorageBitWidth <<
")";
404 return emitError() <<
"expected integer or index type";
407 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
408 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
409 return llvm::cast<BoolAttr>(attr);
417 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
418 return storage->value.getBoolValue();
422 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
423 return intAttr && intAttr.getType().isSignlessInteger(1);
431 StringAttr dialect, StringRef attrData,
434 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
441 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
442 <<
" attribute created with unregistered dialect. If this is "
443 "intended, please call allowUnregisteredDialects() on the "
444 "MLIRContext, or use -allow-unregistered-dialect with "
445 "the MLIR opt tool used";
461 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
468 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
470 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
472 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
476 static bool getBit(
const char *rawData,
size_t bitPos) {
477 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
484 assert(llvm::endianness::native == llvm::endianness::big);
485 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
490 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
491 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
492 numFilledWords, result);
496 size_t lastWordPos = numFilledWords;
498 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
499 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
500 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
504 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
505 valueLE.begin(), result + lastWordPos,
506 (numBytes - lastWordPos) * CHAR_BIT, 1);
513 assert(llvm::endianness::native == llvm::endianness::big);
514 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
521 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
523 inArray, numFilledWords,
524 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
529 size_t lastWordPos = numFilledWords;
531 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
532 inArray + lastWordPos, inArrayLE.begin(),
533 (numBytes - lastWordPos) * CHAR_BIT, 1);
537 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
539 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
541 APInt::APINT_BITS_PER_WORD, 1);
545 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
546 size_t bitWidth = value.getBitWidth();
550 return setBit(rawData, bitPos, value.isOne());
553 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
554 if (llvm::endianness::native == llvm::endianness::big) {
561 rawData + (bitPos / CHAR_BIT));
563 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
565 rawData + (bitPos / CHAR_BIT));
571 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
574 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
577 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
578 APInt result(bitWidth, 0);
579 if (llvm::endianness::native == llvm::endianness::big) {
588 std::copy_n(rawData + (bitPos / CHAR_BIT),
591 reinterpret_cast<const char *
>(result.getRawData())));
598 template <
typename Values>
600 return (values.size() == 1) ||
601 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
612 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
614 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
616 attr.getAsOpaquePointer(), index) {}
620 Type eltTy = owner.getElementType();
621 if (llvm::dyn_cast<IntegerType>(eltTy))
623 if (llvm::isa<IndexType>(eltTy))
625 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
630 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
631 auto complexEltTy = complexTy.getElementType();
633 if (llvm::isa<IntegerType>(complexEltTy)) {
634 auto value = *complexIntIt;
642 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
643 auto value = *complexFloatIt;
649 if (llvm::isa<DenseStringElementsAttr>(owner)) {
651 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
653 llvm_unreachable(
"unexpected element type");
660 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
666 return getBit(getData(), getDataIndex());
673 DenseElementsAttr::IntElementIterator::IntElementIterator(
689 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
692 std::complex<APInt>, std::complex<APInt>,
693 std::complex<APInt>>(
695 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
702 size_t offset = getDataIndex() * storageWidth * 2;
703 return {
readBits(getData(), offset, bitWidth),
704 readBits(getData(), offset + storageWidth, bitWidth)};
715 return emitError() <<
"expected integer or floating point element type";
716 int64_t dataSize = rawData.size();
717 int64_t elementSize =
719 if (
size * elementSize != dataSize) {
720 return emitError() <<
"expected data size (" <<
size <<
" elements, "
722 <<
" bytes each) does not match: " << dataSize
731 template <
size_t width,
732 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
733 struct DenseArrayAttrIntUtil {
734 static bool checkElementType(
Type eltType) {
735 auto type = llvm::dyn_cast<IntegerType>(eltType);
736 if (!type || type.getWidth() != width)
738 return type.getSignedness() == signedness;
745 template <
typename T>
746 static void printElement(raw_ostream &os, T value) {
750 template <
typename T>
751 static ParseResult parseElement(
AsmParser &parser, T &value) {
755 template <
typename T>
756 struct DenseArrayAttrUtil;
761 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
762 static void printElement(raw_ostream &os,
bool value) {
763 os << (value ?
"true" :
"false");
770 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
771 static void printElement(raw_ostream &os, int8_t value) {
772 os << static_cast<int>(value);
776 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
778 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
780 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
784 struct DenseArrayAttrUtil<float> {
785 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
787 static void printElement(raw_ostream &os,
float value) { os << value; }
790 static ParseResult parseElement(
AsmParser &parser,
float &value) {
801 struct DenseArrayAttrUtil<double> {
802 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
804 static void printElement(raw_ostream &os,
float value) { os << value; }
805 static ParseResult parseElement(
AsmParser &parser,
double &value) {
811 template <
typename T>
816 template <
typename T>
818 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
819 DenseArrayAttrUtil<T>::printElement(os, value);
823 template <
typename T>
826 printWithoutBraces(os);
831 template <
typename T>
837 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
839 data.push_back(value);
847 template <
typename T>
854 Attribute result = parseWithoutBraces(parser, odsType);
861 template <
typename T>
864 assert((raw.size() %
sizeof(T)) == 0);
865 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
866 raw.size() /
sizeof(T));
870 template <
typename T>
874 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
875 content.size() *
sizeof(T));
876 return llvm::cast<DenseArrayAttrImpl<T>>(
877 Base::get(context, elementType, content.size(), rawArray));
880 template <
typename T>
882 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
883 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
906 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
913 Type eltType = type.getElementType();
916 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
917 if (complexType.getElementType().isIntOrIndex()) {
919 complexValues.reserve(values.size());
921 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
922 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
923 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
924 auto attr0 = arrayAttr[0];
925 auto attr1 = arrayAttr[1];
926 complexValues.push_back(
927 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
928 llvm::cast<IntegerAttr>(attr1).getValue()));
934 complexValues.reserve(values.size());
936 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
937 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
938 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
939 auto attr0 = arrayAttr[0];
940 auto attr1 = arrayAttr[1];
941 complexValues.push_back(
942 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
943 llvm::cast<FloatAttr>(attr1).getValue()));
952 stringValues.reserve(values.size());
954 assert(llvm::isa<StringAttr>(attr) &&
955 "expected string value for non integer/index/float element");
956 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
958 return get(type, stringValues);
969 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
970 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
971 assert(floatAttr.getType() == eltType &&
972 "expected float attribute type to equal element type");
973 intVal = floatAttr.getValue().bitcastToAPInt();
975 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
976 assert(intAttr.getType() == eltType &&
977 "expected integer attribute type to equal element type");
978 intVal = intAttr.getValue();
981 assert(intVal.getBitWidth() == bitWidth &&
982 "expected value to have same bitwidth as element type");
983 writeBits(data.data(), i * storageBitWidth, intVal);
987 if (values.size() == 1 && eltType.
isInteger(1))
988 data[0] = data[0] ? -1 : 0;
990 return DenseIntOrFPElementsAttr::getRaw(type, data);
996 assert(type.getElementType().isInteger(1));
1000 if (!values.empty()) {
1002 bool firstValue = values[0];
1003 for (
int i = 0, e = values.size(); i != e; ++i) {
1004 isSplat &= values[i] == firstValue;
1005 setBit(buff.data(), i, values[i]);
1011 buff[0] = values[0] ? -1 : 0;
1015 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1020 assert(!type.getElementType().isIntOrFloat());
1029 assert(type.getElementType().isIntOrIndex());
1032 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1035 ArrayRef<std::complex<APInt>> values) {
1036 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1037 assert(llvm::isa<IntegerType>(complex.getElementType()));
1040 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1042 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1050 assert(llvm::isa<FloatType>(type.getElementType()));
1053 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1057 ArrayRef<std::complex<APFloat>> values) {
1058 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1059 assert(llvm::isa<FloatType>(complex.getElementType()));
1064 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1072 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1078 bool &detectedSplat) {
1080 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1081 int64_t numElements = type.getNumElements();
1084 detectedSplat = numElements == 1;
1087 if (storageWidth == 1) {
1090 if (rawBuffer.size() == 1) {
1091 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1092 if (rawByte == 0 || rawByte == 0xff) {
1093 detectedSplat =
true;
1099 return rawBufferWidth == llvm::alignTo<8>(numElements);
1104 if (rawBufferWidth == storageWidth) {
1105 detectedSplat =
true;
1110 return rawBufferWidth == storageWidth * numElements;
1120 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1121 if (denseEltBitWidth != dataSize) {
1122 LLVM_DEBUG(llvm::dbgs() <<
"expected dense element bit width "
1123 << denseEltBitWidth <<
" to match data size "
1124 << dataSize <<
" for type " << type <<
"\n");
1130 bool valid = llvm::isa<FloatType>(type);
1132 LLVM_DEBUG(llvm::dbgs()
1133 <<
"expected float type when isInt is false, but found "
1140 auto intType = llvm::dyn_cast<IntegerType>(type);
1142 LLVM_DEBUG(llvm::dbgs()
1143 <<
"expected integer type when isInt is true, but found " << type
1149 if (intType.isSignless())
1152 bool valid = intType.isSigned() == isSigned;
1154 LLVM_DEBUG(llvm::dbgs() <<
"expected signedness " << isSigned
1155 <<
" to match type " << type <<
"\n");
1162 int64_t dataEltSize,
1163 bool isInt,
bool isSigned) {
1164 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1169 int64_t dataEltSize,
1172 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1177 bool isSigned)
const {
1181 bool isSigned)
const {
1184 dataEltSize / 2, isInt, isSigned);
1195 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1212 const auto &elementSemantics = eltTy.getFloatSemantics();
1223 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1226 const auto &semantics = eltTy.getFloatSemantics();
1228 getType(), {semantics, {*
this, 0}},
1245 ShapedType curType =
getType();
1246 if (curType == newType)
1249 assert(newType.getElementType() == curType.getElementType() &&
1250 "expected the same element type");
1251 assert(newType.getNumElements() == curType.getNumElements() &&
1252 "expected the same number of elements");
1253 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1257 assert(
isSplat() &&
"expected a splat type");
1259 ShapedType curType =
getType();
1260 if (curType == newType)
1263 assert(newType.getElementType() == curType.getElementType() &&
1264 "expected the same element type");
1265 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1273 ShapedType curType =
getType();
1274 Type curElType = curType.getElementType();
1275 if (curElType == newElType)
1280 "expected element types with the same bitwidth");
1281 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1288 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1294 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1303 return getType().getElementType();
1307 return getType().getNumElements();
1315 template <
typename APRangeT>
1318 APRangeT &&values) {
1319 size_t numValues = llvm::size(values);
1322 for (
auto it = values.begin(), e = values.end(); it != e;
1323 ++it, offset += storageWidth) {
1324 assert((*it).getBitWidth() <= storageWidth);
1329 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1330 data[0] = data[0] ? -1 : 0;
1337 size_t storageWidth,
1340 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1342 return DenseIntOrFPElementsAttr::getRaw(type, data);
1349 size_t storageWidth,
1353 return DenseIntOrFPElementsAttr::getRaw(type, data);
1358 assert(type.hasStaticShape() &&
"type must have static shape");
1371 int64_t dataEltSize,
1375 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1376 dataEltSize / 2, isInt, isSigned) &&
1377 "Try re-running with -debug-only=builtinattributes");
1379 int64_t numElements = data.size() / dataEltSize;
1381 assert(numElements == 1 || numElements == type.getNumElements());
1382 return getRaw(type, data);
1389 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1390 int64_t dataEltSize,
bool isInt,
1394 "Try re-running with -debug-only=builtinattributes");
1396 int64_t numElements = data.size() / dataEltSize;
1397 assert(numElements == 1 || numElements == type.getNumElements());
1399 return getRaw(type, data);
1402 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1403 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1404 size_t numElements) {
1405 using llvm::support::ulittle16_t;
1406 using llvm::support::ulittle32_t;
1407 using llvm::support::ulittle64_t;
1409 assert(llvm::endianness::native == llvm::endianness::big);
1413 switch (elementBitWidth) {
1415 const ulittle16_t *inRawDataPos =
1416 reinterpret_cast<const ulittle16_t *
>(inRawData);
1417 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1418 std::copy_n(inRawDataPos, numElements, outDataPos);
1422 const ulittle32_t *inRawDataPos =
1423 reinterpret_cast<const ulittle32_t *
>(inRawData);
1424 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1425 std::copy_n(inRawDataPos, numElements, outDataPos);
1429 const ulittle64_t *inRawDataPos =
1430 reinterpret_cast<const ulittle64_t *
>(inRawData);
1431 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1432 std::copy_n(inRawDataPos, numElements, outDataPos);
1436 size_t nBytes = elementBitWidth / CHAR_BIT;
1437 for (
size_t i = 0; i < nBytes; i++)
1438 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1444 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1447 size_t numElements = type.getNumElements();
1448 Type elementType = type.getElementType();
1449 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1450 elementType = complexTy.getElementType();
1451 numElements = numElements * 2;
1454 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1455 inRawData.size() <= outRawData.size());
1456 if (elementBitWidth <= CHAR_BIT)
1457 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1459 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1460 elementBitWidth, numElements);
1467 template <
typename Fn,
typename Attr>
1469 Type newElementType,
1474 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1476 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1480 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1481 auto newInt = mapping(value);
1482 assert(newInt.getBitWidth() == bitWidth);
1483 writeBits(data.data(), index * storageBitWidth, newInt);
1487 if (attr.isSplat()) {
1488 if (bitWidth == 1) {
1490 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1492 processElt(*attr.begin(), 0);
1494 return newArrayType;
1498 uint64_t elementIdx = 0;
1499 for (
auto value : attr)
1500 processElt(value, elementIdx++);
1501 return newArrayType;
1510 return getRaw(newArrayType, elementData);
1515 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1516 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1529 return getRaw(newArrayType, elementData);
1534 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1535 return denseAttr.getType().getElementType().isIntOrIndex();
1546 return Base::get(type.getContext(), type, handle);
1556 return get(type, manager.insert(blobName, std::move(blob)));
1561 return blob->getDataAs<
char>();
1572 template <
typename T>
1573 struct DenseResourceAttrUtil;
1574 template <
size_t w
idth,
bool isSigned>
1575 struct DenseResourceElementsAttrIntUtil {
1576 static bool checkElementType(
Type eltType) {
1577 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1578 if (!type || type.getWidth() != width)
1580 return isSigned ? !type.isUnsigned() : !type.isSigned();
1584 struct DenseResourceAttrUtil<bool> {
1585 static bool checkElementType(
Type eltType) {
1590 struct DenseResourceAttrUtil<int8_t>
1591 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1593 struct DenseResourceAttrUtil<uint8_t>
1594 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1596 struct DenseResourceAttrUtil<int16_t>
1597 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1599 struct DenseResourceAttrUtil<uint16_t>
1600 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1602 struct DenseResourceAttrUtil<int32_t>
1603 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1605 struct DenseResourceAttrUtil<uint32_t>
1606 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1608 struct DenseResourceAttrUtil<int64_t>
1609 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1611 struct DenseResourceAttrUtil<uint64_t>
1612 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1614 struct DenseResourceAttrUtil<float> {
1615 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1618 struct DenseResourceAttrUtil<double> {
1619 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1623 template <
typename T>
1629 "alignment mismatch between expected alignment and blob alignment");
1630 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1631 "size mismatch between expected element width and blob size");
1632 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1633 "invalid shape element type for provided type `T`");
1634 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1638 template <
typename T>
1639 std::optional<ArrayRef<T>>
1642 return blob->template getDataAs<T>();
1643 return std::nullopt;
1646 template <
typename T>
1648 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1649 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1650 resourceAttr.getElementType());
1675 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1677 return APFloat(eltType.getFloatSemantics());
1681 APInt SparseElementsAttr::getZeroAPInt()
const {
1687 Attribute SparseElementsAttr::getZeroAttr()
const {
1691 if (llvm::isa<FloatType>(eltType))
1695 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1696 auto eltType = complexTy.getElementType();
1698 if (llvm::isa<FloatType>(eltType))
1707 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1722 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1723 if (sparseIndices.isSplat()) {
1725 *sparseIndexValues.begin());
1726 flatSparseIndices.push_back(getFlattenedIndex(indices));
1727 return flatSparseIndices;
1731 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1732 size_t rank =
getType().getRank();
1733 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1734 flatSparseIndices.push_back(getFlattenedIndex(
1735 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1736 return flatSparseIndices;
1743 ShapedType valuesType = values.
getType();
1744 if (valuesType.getRank() != 1)
1745 return emitError() <<
"expected 1-d tensor for sparse element values";
1748 ShapedType indicesType = sparseIndices.getType();
1749 auto emitShapeError = [&]() {
1750 return emitError() <<
"expected shape ([" << type.getShape()
1751 <<
"]); inferred shape of indices literal (["
1752 << indicesType.getShape()
1753 <<
"]); inferred shape of values literal (["
1754 << valuesType.getShape() <<
"])";
1757 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1758 if (indicesRank == 2) {
1759 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1760 return emitShapeError();
1761 }
else if (indicesRank != 1 || rank != 1) {
1762 return emitShapeError();
1765 int64_t numSparseIndices = indicesType.getDimSize(0);
1766 if (numSparseIndices != valuesType.getDimSize(0))
1767 return emitShapeError();
1772 <<
"sparse index #" << indexNum
1773 <<
" is not contained within the value shape, with index=[" << index
1774 <<
"], and type=" << type;
1778 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1779 if (sparseIndices.isSplat()) {
1781 if (!ElementsAttr::isValidIndex(type, indices))
1782 return emitIndexError(0, indices);
1787 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1790 if (!ElementsAttr::isValidIndex(type, index))
1791 return emitIndexError(i, index);
1806 return getImpl()->referencedAttr;
1817 unsigned nSymbols = 0;
1821 if (ShapedType::isStatic(offset)) {
1832 auto dim = en.index();
1833 auto stride = en.value();
1837 if (ShapedType::isStatic(stride))
1842 expr = expr + d * mult;
static LogicalResult getStridesAndOffset(AffineMap m, ArrayRef< int64_t > shape, SmallVectorImpl< AffineExpr > &strides, AffineExpr &offset)
A stride specification is a list of integer values that are either static or dynamic (encoded with Sh...
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
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 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 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 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 MLIRContext * getContext(OpFoldResult val)
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
static DimensionSize operator*(DimensionSize lhs, DimensionSize rhs)
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.
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.
ImplType * getImpl() const
Return the internal Attribute implementation.
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.
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.
bool isInteger() const
Return true if this is an integer type (with the specified width).
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.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
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.
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator)
Divides the known min value of the numerator by the denominator and rounds the result up to the next ...
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...
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
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.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
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.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
static const char kSplatTrue
The values used to denote a boolean splat value.
static const char kSplatFalse
An attribute representing a reference to a dense vector or tensor object containing strings.