20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/ADT/Sequence.h"
22 #include "llvm/ADT/TypeSwitch.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/Endian.h"
27 #define DEBUG_TYPE "builtinattributes"
36 #define GET_ATTRDEF_CLASSES
37 #include "mlir/IR/BuiltinAttributes.cpp.inc"
43 void BuiltinDialect::registerAttributes() {
45 #define GET_ATTRDEF_LIST
46 #include "mlir/IR/BuiltinAttributes.cpp.inc"
48 addAttributes<DistinctAttr>();
59 template <
bool inPlace>
63 switch (value.size()) {
72 storage.assign({value[0]});
75 bool isSorted = value[0] < value[1];
78 std::swap(storage[0], storage[1]);
79 }
else if (isSorted) {
80 storage.assign({value[0], value[1]});
82 storage.assign({value[1], value[0]});
88 storage.assign(value.begin(), value.end());
90 bool isSorted = llvm::is_sorted(value);
93 llvm::array_pod_sort(storage.begin(), storage.end());
101 static std::optional<NamedAttribute>
103 const std::optional<NamedAttribute> none{std::nullopt};
104 if (value.size() < 2)
107 if (value.size() == 2)
108 return value[0].getName() == value[1].getName() ? value[0] : none;
110 const auto *it = std::adjacent_find(value.begin(), value.end(),
112 return l.getName() == r.getName();
114 return it != value.end() ? *it : none;
121 "DictionaryAttr element names must be unique");
128 "DictionaryAttr element names must be unique");
132 std::optional<NamedAttribute>
143 return DictionaryAttr::getEmpty(context);
147 if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
150 "DictionaryAttr element names must be unique");
155 DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
158 return DictionaryAttr::getEmpty(context);
160 assert(llvm::is_sorted(
162 "expected attribute values to be sorted");
164 "DictionaryAttr element names must be unique");
171 return it.second ? it.first->getValue() :
Attribute();
175 return it.second ? it.first->getValue() :
Attribute();
179 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
181 return it.second ? *it.first : std::optional<NamedAttribute>();
183 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
185 return it.second ? *it.first : std::optional<NamedAttribute>();
196 DictionaryAttr::iterator DictionaryAttr::begin()
const {
197 return getValue().begin();
199 DictionaryAttr::iterator DictionaryAttr::end()
const {
200 return getValue().end();
202 size_t DictionaryAttr::size()
const {
return getValue().size(); }
204 DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
214 auto printIntOrQuestion = [&](int64_t value) {
215 if (ShapedType::isDynamic(value))
222 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
225 if (getOffset() != 0) {
227 printIntOrQuestion(getOffset());
233 AffineMap StridedLayoutAttr::getAffineMap()
const {
241 if (llvm::is_contained(strides, 0))
242 return emitError() <<
"strides must not be zero";
251 if (shape.size() != getStrides().size())
252 return emitError() <<
"expected the number of strides to match the rank";
261 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
268 if (twine.isTriviallyEmpty())
280 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
282 Type StringAttr::getType()
const {
return getImpl()->type; }
284 Dialect *StringAttr::getReferencedDialect()
const {
285 return getImpl()->referencedDialect;
292 double FloatAttr::getValueAsDouble()
const {
293 return getValueAsDouble(getValue());
295 double FloatAttr::getValueAsDouble(APFloat value) {
296 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
297 bool losesInfo =
false;
298 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
301 return value.convertToDouble();
305 Type type, APFloat value) {
307 if (!llvm::isa<FloatType>(type))
308 return emitError() <<
"expected floating point type";
311 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
312 &value.getSemantics()) {
314 <<
"FloatAttr type doesn't match the type implied by its value";
329 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
333 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
339 assert(symName &&
"value does not have a valid symbol name");
343 StringAttr SymbolRefAttr::getLeafReference()
const {
345 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
352 int64_t IntegerAttr::getInt()
const {
353 assert((getType().isIndex() || getType().isSignlessInteger()) &&
354 "must be signless integer");
355 return getValue().getSExtValue();
358 int64_t IntegerAttr::getSInt()
const {
359 assert(getType().isSignedInteger() &&
"must be signed integer");
360 return getValue().getSExtValue();
363 uint64_t IntegerAttr::getUInt()
const {
364 assert(getType().isUnsignedInteger() &&
"must be unsigned integer");
365 return getValue().getZExtValue();
370 APSInt IntegerAttr::getAPSInt()
const {
371 assert(!getType().isSignlessInteger() &&
372 "Signless integers don't carry a sign for APSInt");
373 return APSInt(getValue(), getType().isUnsignedInteger());
377 Type type, APInt value) {
378 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
379 if (integerType.getWidth() != value.getBitWidth())
380 return emitError() <<
"integer type bit width (" << integerType.getWidth()
381 <<
") doesn't match value bit width ("
382 << value.getBitWidth() <<
")";
385 if (llvm::isa<IndexType>(type)) {
386 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
388 <<
"value bit width (" << value.getBitWidth()
389 <<
") doesn't match index type internal storage bit width ("
390 << IndexType::kInternalStorageBitWidth <<
")";
393 return emitError() <<
"expected integer or index type";
396 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
397 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
398 return llvm::cast<BoolAttr>(attr);
406 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
407 return storage->value.getBoolValue();
411 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
412 return intAttr && intAttr.getType().isSignlessInteger(1);
420 StringAttr dialect, StringRef attrData,
423 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
430 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
431 <<
" attribute created with unregistered dialect. If this is "
432 "intended, please call allowUnregisteredDialects() on the "
433 "MLIRContext, or use -allow-unregistered-dialect with "
434 "the MLIR opt tool used";
450 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
457 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
459 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
461 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
465 static bool getBit(
const char *rawData,
size_t bitPos) {
466 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
473 assert(llvm::endianness::native == llvm::endianness::big);
474 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
479 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
480 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
481 numFilledWords, result);
485 size_t lastWordPos = numFilledWords;
487 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
488 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
489 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
493 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
494 valueLE.begin(), result + lastWordPos,
495 (numBytes - lastWordPos) * CHAR_BIT, 1);
502 assert(llvm::endianness::native == llvm::endianness::big);
503 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
510 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
512 inArray, numFilledWords,
513 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
518 size_t lastWordPos = numFilledWords;
520 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
521 inArray + lastWordPos, inArrayLE.begin(),
522 (numBytes - lastWordPos) * CHAR_BIT, 1);
526 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
528 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
530 APInt::APINT_BITS_PER_WORD, 1);
534 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
535 size_t bitWidth = value.getBitWidth();
539 return setBit(rawData, bitPos, value.isOne());
542 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
543 if (llvm::endianness::native == llvm::endianness::big) {
550 rawData + (bitPos / CHAR_BIT));
552 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
554 rawData + (bitPos / CHAR_BIT));
560 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
563 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
566 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
567 APInt result(bitWidth, 0);
568 if (llvm::endianness::native == llvm::endianness::big) {
577 std::copy_n(rawData + (bitPos / CHAR_BIT),
580 reinterpret_cast<const char *
>(result.getRawData())));
587 template <
typename Values>
589 return (values.size() == 1) ||
590 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
600 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
602 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
604 attr.getAsOpaquePointer(), index) {}
608 Type eltTy = owner.getElementType();
609 if (llvm::dyn_cast<IntegerType>(eltTy))
611 if (llvm::isa<IndexType>(eltTy))
613 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
618 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
619 auto complexEltTy = complexTy.getElementType();
621 if (llvm::isa<IntegerType>(complexEltTy)) {
622 auto value = *complexIntIt;
630 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
631 auto value = *complexFloatIt;
637 if (llvm::isa<DenseStringElementsAttr>(owner)) {
639 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
641 llvm_unreachable(
"unexpected element type");
647 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
653 return getBit(getData(), getDataIndex());
659 DenseElementsAttr::IntElementIterator::IntElementIterator(
674 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
677 std::complex<APInt>, std::complex<APInt>,
678 std::complex<APInt>>(
680 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
687 size_t offset = getDataIndex() * storageWidth * 2;
688 return {
readBits(getData(), offset, bitWidth),
689 readBits(getData(), offset + storageWidth, bitWidth)};
700 return emitError() <<
"expected integer or floating point element type";
701 int64_t dataSize = rawData.size();
702 int64_t elementSize =
704 if (
size * elementSize != dataSize) {
705 return emitError() <<
"expected data size (" <<
size <<
" elements, "
707 <<
" bytes each) does not match: " << dataSize
716 template <
size_t width,
717 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
718 struct DenseArrayAttrIntUtil {
719 static bool checkElementType(
Type eltType) {
720 auto type = llvm::dyn_cast<IntegerType>(eltType);
721 if (!type || type.getWidth() != width)
723 return type.getSignedness() == signedness;
730 template <
typename T>
731 static void printElement(raw_ostream &os, T value) {
735 template <
typename T>
740 template <
typename T>
741 struct DenseArrayAttrUtil;
746 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
747 static void printElement(raw_ostream &os,
bool value) {
748 os << (value ?
"true" :
"false");
755 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
756 static void printElement(raw_ostream &os, int8_t value) {
757 os << static_cast<int>(value);
761 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
763 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
765 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
769 struct DenseArrayAttrUtil<float> {
770 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
772 static void printElement(raw_ostream &os,
float value) { os << value; }
786 struct DenseArrayAttrUtil<double> {
787 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
789 static void printElement(raw_ostream &os,
float value) { os << value; }
796 template <
typename T>
801 template <
typename T>
803 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
804 DenseArrayAttrUtil<T>::printElement(os, value);
808 template <
typename T>
811 printWithoutBraces(os);
816 template <
typename T>
822 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
824 data.push_back(value);
832 template <
typename T>
839 Attribute result = parseWithoutBraces(parser, odsType);
846 template <
typename T>
849 assert((raw.size() %
sizeof(T)) == 0);
850 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
851 raw.size() /
sizeof(T));
855 template <
typename T>
859 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
860 content.size() *
sizeof(T));
861 return llvm::cast<DenseArrayAttrImpl<T>>(
862 Base::get(context, elementType, content.size(), rawArray));
865 template <
typename T>
867 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
868 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
891 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
898 Type eltType = type.getElementType();
901 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
902 if (complexType.getElementType().isIntOrIndex()) {
904 complexValues.reserve(values.size());
906 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
907 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
908 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
909 auto attr0 = arrayAttr[0];
910 auto attr1 = arrayAttr[1];
911 complexValues.push_back(
912 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
913 llvm::cast<IntegerAttr>(attr1).getValue()));
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<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
928 llvm::cast<FloatAttr>(attr1).getValue()));
937 stringValues.reserve(values.size());
939 assert(llvm::isa<StringAttr>(attr) &&
940 "expected string value for non integer/index/float element");
941 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
943 return get(type, stringValues);
954 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
955 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
956 assert(floatAttr.getType() == eltType &&
957 "expected float attribute type to equal element type");
958 intVal = floatAttr.getValue().bitcastToAPInt();
960 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
961 assert(intAttr.getType() == eltType &&
962 "expected integer attribute type to equal element type");
963 intVal = intAttr.getValue();
966 assert(intVal.getBitWidth() == bitWidth &&
967 "expected value to have same bitwidth as element type");
968 writeBits(data.data(), i * storageBitWidth, intVal);
972 if (values.size() == 1 && eltType.
isInteger(1))
973 data[0] = data[0] ? -1 : 0;
975 return DenseIntOrFPElementsAttr::getRaw(type, data);
981 assert(type.getElementType().isInteger(1));
985 if (!values.empty()) {
987 bool firstValue = values[0];
988 for (
int i = 0, e = values.size(); i != e; ++i) {
989 isSplat &= values[i] == firstValue;
990 setBit(buff.data(), i, values[i]);
996 buff[0] = values[0] ? -1 : 0;
1000 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1005 assert(!type.getElementType().isIntOrFloat());
1014 assert(type.getElementType().isIntOrIndex());
1017 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1020 ArrayRef<std::complex<APInt>> values) {
1021 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1022 assert(llvm::isa<IntegerType>(complex.getElementType()));
1025 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1027 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1035 assert(llvm::isa<FloatType>(type.getElementType()));
1038 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1042 ArrayRef<std::complex<APFloat>> values) {
1043 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1044 assert(llvm::isa<FloatType>(complex.getElementType()));
1049 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1057 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1063 bool &detectedSplat) {
1065 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1066 int64_t numElements = type.getNumElements();
1069 detectedSplat = numElements == 1;
1072 if (storageWidth == 1) {
1075 if (rawBuffer.size() == 1) {
1076 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1077 if (rawByte == 0 || rawByte == 0xff) {
1078 detectedSplat =
true;
1084 return rawBufferWidth == llvm::alignTo<8>(numElements);
1089 if (rawBufferWidth == storageWidth) {
1090 detectedSplat =
true;
1095 return rawBufferWidth == storageWidth * numElements;
1105 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1106 if (denseEltBitWidth != dataSize) {
1107 LLVM_DEBUG(llvm::dbgs() <<
"expected dense element bit width "
1108 << denseEltBitWidth <<
" to match data size "
1109 << dataSize <<
" for type " << type <<
"\n");
1115 bool valid = llvm::isa<FloatType>(type);
1117 LLVM_DEBUG(llvm::dbgs()
1118 <<
"expected float type when isInt is false, but found "
1125 auto intType = llvm::dyn_cast<IntegerType>(type);
1127 LLVM_DEBUG(llvm::dbgs()
1128 <<
"expected integer type when isInt is true, but found " << type
1134 if (intType.isSignless())
1137 bool valid = intType.isSigned() == isSigned;
1139 LLVM_DEBUG(llvm::dbgs() <<
"expected signedness " << isSigned
1140 <<
" to match type " << type <<
"\n");
1147 int64_t dataEltSize,
1148 bool isInt,
bool isSigned) {
1149 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1154 int64_t dataEltSize,
1157 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1162 bool isSigned)
const {
1166 bool isSigned)
const {
1169 dataEltSize / 2, isInt, isSigned);
1180 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1197 const auto &elementSemantics = eltTy.getFloatSemantics();
1208 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1211 const auto &semantics = eltTy.getFloatSemantics();
1213 getType(), {semantics, {*
this, 0}},
1230 ShapedType curType =
getType();
1231 if (curType == newType)
1234 assert(newType.getElementType() == curType.getElementType() &&
1235 "expected the same element type");
1236 assert(newType.getNumElements() == curType.getNumElements() &&
1237 "expected the same number of elements");
1238 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1242 assert(
isSplat() &&
"expected a splat type");
1244 ShapedType curType =
getType();
1245 if (curType == newType)
1248 assert(newType.getElementType() == curType.getElementType() &&
1249 "expected the same element type");
1250 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1258 ShapedType curType =
getType();
1259 Type curElType = curType.getElementType();
1260 if (curElType == newElType)
1265 "expected element types with the same bitwidth");
1266 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1273 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1279 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1288 return getType().getElementType();
1292 return getType().getNumElements();
1300 template <
typename APRangeT>
1302 APRangeT &&values) {
1303 size_t numValues = llvm::size(values);
1306 for (
auto it = values.begin(), e = values.end(); it != e;
1307 ++it, offset += storageWidth) {
1308 assert((*it).getBitWidth() <= storageWidth);
1313 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1314 data[0] = data[0] ? -1 : 0;
1321 size_t storageWidth,
1323 std::vector<char> data;
1324 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1326 return DenseIntOrFPElementsAttr::getRaw(type, data);
1333 size_t storageWidth,
1335 std::vector<char> data;
1337 return DenseIntOrFPElementsAttr::getRaw(type, data);
1342 assert(type.hasStaticShape() &&
"type must have static shape");
1355 int64_t dataEltSize,
1359 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1360 dataEltSize / 2, isInt, isSigned) &&
1361 "Try re-running with -debug-only=builtinattributes");
1363 int64_t numElements = data.size() / dataEltSize;
1365 assert(numElements == 1 || numElements == type.getNumElements());
1366 return getRaw(type, data);
1373 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1374 int64_t dataEltSize,
bool isInt,
1378 "Try re-running with -debug-only=builtinattributes");
1380 int64_t numElements = data.size() / dataEltSize;
1381 assert(numElements == 1 || numElements == type.getNumElements());
1383 return getRaw(type, data);
1386 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1387 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1388 size_t numElements) {
1389 using llvm::support::ulittle16_t;
1390 using llvm::support::ulittle32_t;
1391 using llvm::support::ulittle64_t;
1393 assert(llvm::endianness::native == llvm::endianness::big);
1397 switch (elementBitWidth) {
1399 const ulittle16_t *inRawDataPos =
1400 reinterpret_cast<const ulittle16_t *
>(inRawData);
1401 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1402 std::copy_n(inRawDataPos, numElements, outDataPos);
1406 const ulittle32_t *inRawDataPos =
1407 reinterpret_cast<const ulittle32_t *
>(inRawData);
1408 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1409 std::copy_n(inRawDataPos, numElements, outDataPos);
1413 const ulittle64_t *inRawDataPos =
1414 reinterpret_cast<const ulittle64_t *
>(inRawData);
1415 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1416 std::copy_n(inRawDataPos, numElements, outDataPos);
1420 size_t nBytes = elementBitWidth / CHAR_BIT;
1421 for (
size_t i = 0; i < nBytes; i++)
1422 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1428 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1431 size_t numElements = type.getNumElements();
1432 Type elementType = type.getElementType();
1433 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1434 elementType = complexTy.getElementType();
1435 numElements = numElements * 2;
1438 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1439 inRawData.size() <= outRawData.size());
1440 if (elementBitWidth <= CHAR_BIT)
1441 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1443 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1444 elementBitWidth, numElements);
1451 template <
typename Fn,
typename Attr>
1453 Type newElementType,
1458 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1460 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1464 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1465 auto newInt = mapping(value);
1466 assert(newInt.getBitWidth() == bitWidth);
1467 writeBits(data.data(), index * storageBitWidth, newInt);
1471 if (attr.isSplat()) {
1472 if (bitWidth == 1) {
1474 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1476 processElt(*attr.begin(), 0);
1478 return newArrayType;
1482 uint64_t elementIdx = 0;
1483 for (
auto value : attr)
1484 processElt(value, elementIdx++);
1485 return newArrayType;
1494 return getRaw(newArrayType, elementData);
1499 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1500 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1513 return getRaw(newArrayType, elementData);
1518 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1519 return denseAttr.getType().getElementType().isIntOrIndex();
1530 return Base::get(type.getContext(), type, handle);
1540 return get(type, manager.insert(blobName, std::move(blob)));
1549 template <
typename T>
1550 struct DenseResourceAttrUtil;
1551 template <
size_t w
idth,
bool isSigned>
1552 struct DenseResourceElementsAttrIntUtil {
1553 static bool checkElementType(
Type eltType) {
1554 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1555 if (!type || type.getWidth() != width)
1557 return isSigned ? !type.isUnsigned() : !type.isSigned();
1561 struct DenseResourceAttrUtil<bool> {
1562 static bool checkElementType(
Type eltType) {
1567 struct DenseResourceAttrUtil<int8_t>
1568 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1570 struct DenseResourceAttrUtil<uint8_t>
1571 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1573 struct DenseResourceAttrUtil<int16_t>
1574 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1576 struct DenseResourceAttrUtil<uint16_t>
1577 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1579 struct DenseResourceAttrUtil<int32_t>
1580 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1582 struct DenseResourceAttrUtil<uint32_t>
1583 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1585 struct DenseResourceAttrUtil<int64_t>
1586 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1588 struct DenseResourceAttrUtil<uint64_t>
1589 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1591 struct DenseResourceAttrUtil<float> {
1592 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1595 struct DenseResourceAttrUtil<double> {
1596 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1600 template <
typename T>
1606 "alignment mismatch between expected alignment and blob alignment");
1607 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1608 "size mismatch between expected element width and blob size");
1609 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1610 "invalid shape element type for provided type `T`");
1611 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1615 template <
typename T>
1616 std::optional<ArrayRef<T>>
1619 return blob->template getDataAs<T>();
1620 return std::nullopt;
1623 template <
typename T>
1625 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1626 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1627 resourceAttr.getElementType());
1652 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1654 return APFloat(eltType.getFloatSemantics());
1658 APInt SparseElementsAttr::getZeroAPInt()
const {
1664 Attribute SparseElementsAttr::getZeroAttr()
const {
1668 if (llvm::isa<FloatType>(eltType))
1672 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1673 auto eltType = complexTy.getElementType();
1675 if (llvm::isa<FloatType>(eltType))
1684 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1693 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1694 std::vector<ptrdiff_t> flatSparseIndices;
1699 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1700 if (sparseIndices.isSplat()) {
1702 *sparseIndexValues.begin());
1703 flatSparseIndices.push_back(getFlattenedIndex(indices));
1704 return flatSparseIndices;
1708 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1709 size_t rank =
getType().getRank();
1710 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1711 flatSparseIndices.push_back(getFlattenedIndex(
1712 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1713 return flatSparseIndices;
1720 ShapedType valuesType = values.
getType();
1721 if (valuesType.getRank() != 1)
1722 return emitError() <<
"expected 1-d tensor for sparse element values";
1725 ShapedType indicesType = sparseIndices.getType();
1726 auto emitShapeError = [&]() {
1727 return emitError() <<
"expected shape ([" << type.getShape()
1728 <<
"]); inferred shape of indices literal (["
1729 << indicesType.getShape()
1730 <<
"]); inferred shape of values literal (["
1731 << valuesType.getShape() <<
"])";
1734 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1735 if (indicesRank == 2) {
1736 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1737 return emitShapeError();
1738 }
else if (indicesRank != 1 || rank != 1) {
1739 return emitShapeError();
1742 int64_t numSparseIndices = indicesType.getDimSize(0);
1743 if (numSparseIndices != valuesType.getDimSize(0))
1744 return emitShapeError();
1749 <<
"sparse index #" << indexNum
1750 <<
" is not contained within the value shape, with index=[" << index
1751 <<
"], and type=" << type;
1755 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1756 if (sparseIndices.isSplat()) {
1758 if (!ElementsAttr::isValidIndex(type, indices))
1759 return emitIndexError(0, indices);
1764 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1767 if (!ElementsAttr::isValidIndex(type, index))
1768 return emitIndexError(i, index);
1783 return getImpl()->referencedAttr;
1794 unsigned nSymbols = 0;
1798 if (!ShapedType::isDynamic(offset)) {
1809 auto dim = en.index();
1810 auto stride = en.value();
1811 assert(stride != 0 &&
"Invalid stride specification");
1815 if (!ShapedType::isDynamic(stride))
1820 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 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.
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.
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.
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.
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.
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.
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.