20 #include "llvm/ADT/APSInt.h"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/DebugLog.h"
23 #include "llvm/Support/Endian.h"
26 #define DEBUG_TYPE "builtinattributes"
35 #define GET_ATTRDEF_CLASSES
36 #include "mlir/IR/BuiltinAttributes.cpp.inc"
42 void BuiltinDialect::registerAttributes() {
44 #define GET_ATTRDEF_LIST
45 #include "mlir/IR/BuiltinAttributes.cpp.inc"
47 addAttributes<DistinctAttr>();
58 template <
bool inPlace>
62 switch (value.size()) {
71 storage.assign({value[0]});
74 bool isSorted = value[0] < value[1];
77 std::swap(storage[0], storage[1]);
78 }
else if (isSorted) {
79 storage.assign({value[0], value[1]});
81 storage.assign({value[1], value[0]});
87 storage.assign(value.begin(), value.end());
89 bool isSorted = llvm::is_sorted(value);
92 llvm::array_pod_sort(storage.begin(), storage.end());
100 static std::optional<NamedAttribute>
102 const std::optional<NamedAttribute> none{std::nullopt};
103 if (value.size() < 2)
106 if (value.size() == 2)
107 return value[0].getName() == value[1].getName() ? value[0] : none;
109 const auto *it = std::adjacent_find(value.begin(), value.end(),
111 return l.getName() == r.getName();
113 return it != value.end() ? *it : none;
120 "DictionaryAttr element names must be unique");
127 "DictionaryAttr element names must be unique");
131 std::optional<NamedAttribute>
142 return DictionaryAttr::getEmpty(context);
146 if (dictionaryAttrSort</*inPlace=*/false>(value, storage))
149 "DictionaryAttr element names must be unique");
154 DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
157 return DictionaryAttr::getEmpty(context);
159 assert(llvm::is_sorted(
161 "expected attribute values to be sorted");
163 "DictionaryAttr element names must be unique");
170 return it.second ? it.first->getValue() :
Attribute();
174 return it.second ? it.first->getValue() :
Attribute();
178 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
180 return it.second ? *it.first : std::optional<NamedAttribute>();
182 std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
184 return it.second ? *it.first : std::optional<NamedAttribute>();
195 DictionaryAttr::iterator DictionaryAttr::begin()
const {
196 return getValue().begin();
198 DictionaryAttr::iterator DictionaryAttr::end()
const {
199 return getValue().end();
201 size_t DictionaryAttr::size()
const {
return getValue().size(); }
203 DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
213 auto printIntOrQuestion = [&](int64_t value) {
214 if (ShapedType::isDynamic(value))
221 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
224 if (getOffset() != 0) {
226 printIntOrQuestion(getOffset());
233 bool StridedLayoutAttr::hasStaticLayout()
const {
234 return ShapedType::isStatic(getOffset()) &&
235 ShapedType::isStaticShape(getStrides());
239 AffineMap StridedLayoutAttr::getAffineMap()
const {
251 LogicalResult StridedLayoutAttr::verifyLayout(
254 if (shape.size() != getStrides().size())
255 return emitError() <<
"expected the number of strides to match the rank";
263 int64_t &offset)
const {
264 llvm::append_range(strides, getStrides());
265 offset = getOffset();
273 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
280 if (twine.isTriviallyEmpty())
292 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
296 Dialect *StringAttr::getReferencedDialect()
const {
297 return getImpl()->referencedDialect;
304 double FloatAttr::getValueAsDouble()
const {
305 return getValueAsDouble(getValue());
307 double FloatAttr::getValueAsDouble(APFloat value) {
308 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
309 bool losesInfo =
false;
310 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
313 return value.convertToDouble();
317 Type type, APFloat value) {
319 if (!llvm::isa<FloatType>(type))
320 return emitError() <<
"expected floating point type";
323 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
324 &value.getSemantics()) {
326 <<
"FloatAttr type doesn't match the type implied by its value";
341 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
345 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
351 assert(symName &&
"value does not have a valid symbol name");
355 StringAttr SymbolRefAttr::getLeafReference()
const {
357 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
364 int64_t IntegerAttr::getInt()
const {
366 "must be signless integer");
367 return getValue().getSExtValue();
370 int64_t IntegerAttr::getSInt()
const {
371 assert(
getType().isSignedInteger() &&
"must be signed integer");
372 return getValue().getSExtValue();
375 uint64_t IntegerAttr::getUInt()
const {
376 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
377 return getValue().getZExtValue();
382 APSInt IntegerAttr::getAPSInt()
const {
383 assert(!
getType().isSignlessInteger() &&
384 "Signless integers don't carry a sign for APSInt");
385 return APSInt(getValue(),
getType().isUnsignedInteger());
389 Type type, APInt value) {
390 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
391 if (integerType.getWidth() != value.getBitWidth())
392 return emitError() <<
"integer type bit width (" << integerType.getWidth()
393 <<
") doesn't match value bit width ("
394 << value.getBitWidth() <<
")";
397 if (llvm::isa<IndexType>(type)) {
398 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
400 <<
"value bit width (" << value.getBitWidth()
401 <<
") doesn't match index type internal storage bit width ("
402 << IndexType::kInternalStorageBitWidth <<
")";
405 return emitError() <<
"expected integer or index type";
408 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
409 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
410 return llvm::cast<BoolAttr>(attr);
418 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
419 return storage->value.getBoolValue();
423 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
424 return intAttr && intAttr.getType().isSignlessInteger(1);
432 StringAttr dialect, StringRef attrData,
435 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
442 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
443 <<
" attribute created with unregistered dialect. If this is "
444 "intended, please call allowUnregisteredDialects() on the "
445 "MLIRContext, or use -allow-unregistered-dialect with "
446 "the MLIR opt tool used";
462 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
469 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
471 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
473 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
477 static bool getBit(
const char *rawData,
size_t bitPos) {
478 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
485 assert(llvm::endianness::native == llvm::endianness::big);
486 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
491 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
492 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
493 numFilledWords, result);
497 size_t lastWordPos = numFilledWords;
499 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
500 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
501 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
505 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
506 valueLE.begin(), result + lastWordPos,
507 (numBytes - lastWordPos) * CHAR_BIT, 1);
514 assert(llvm::endianness::native == llvm::endianness::big);
515 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
522 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
524 inArray, numFilledWords,
525 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
530 size_t lastWordPos = numFilledWords;
532 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
533 inArray + lastWordPos, inArrayLE.begin(),
534 (numBytes - lastWordPos) * CHAR_BIT, 1);
538 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
540 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
542 APInt::APINT_BITS_PER_WORD, 1);
546 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
547 size_t bitWidth = value.getBitWidth();
551 return setBit(rawData, bitPos, value.isOne());
554 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
555 if (llvm::endianness::native == llvm::endianness::big) {
562 rawData + (bitPos / CHAR_BIT));
564 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
566 rawData + (bitPos / CHAR_BIT));
572 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
575 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
578 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
579 APInt result(bitWidth, 0);
580 if (llvm::endianness::native == llvm::endianness::big) {
589 std::copy_n(rawData + (bitPos / CHAR_BIT),
592 reinterpret_cast<const char *
>(result.getRawData())));
599 template <
typename Values>
601 return (values.size() == 1) ||
602 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
613 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
615 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
617 attr.getAsOpaquePointer(), index) {}
621 Type eltTy = owner.getElementType();
622 if (llvm::dyn_cast<IntegerType>(eltTy))
624 if (llvm::isa<IndexType>(eltTy))
626 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
631 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
632 auto complexEltTy = complexTy.getElementType();
634 if (llvm::isa<IntegerType>(complexEltTy)) {
635 auto value = *complexIntIt;
643 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
644 auto value = *complexFloatIt;
650 if (llvm::isa<DenseStringElementsAttr>(owner)) {
652 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
654 llvm_unreachable(
"unexpected element type");
661 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
667 return getBit(getData(), getDataIndex());
674 DenseElementsAttr::IntElementIterator::IntElementIterator(
690 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
693 std::complex<APInt>, std::complex<APInt>,
694 std::complex<APInt>>(
696 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
703 size_t offset = getDataIndex() * storageWidth * 2;
704 return {
readBits(getData(), offset, bitWidth),
705 readBits(getData(), offset + storageWidth, bitWidth)};
716 return emitError() <<
"expected integer or floating point element type";
717 int64_t dataSize = rawData.size();
718 int64_t elementSize =
720 if (
size * elementSize != dataSize) {
721 return emitError() <<
"expected data size (" <<
size <<
" elements, "
723 <<
" bytes each) does not match: " << dataSize
732 template <
size_t width,
733 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
734 struct DenseArrayAttrIntUtil {
735 static bool checkElementType(
Type eltType) {
736 auto type = llvm::dyn_cast<IntegerType>(eltType);
737 if (!type || type.getWidth() != width)
739 return type.getSignedness() == signedness;
746 template <
typename T>
747 static void printElement(raw_ostream &os, T value) {
751 template <
typename T>
752 static ParseResult parseElement(
AsmParser &parser, T &value) {
756 template <
typename T>
757 struct DenseArrayAttrUtil;
762 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
763 static void printElement(raw_ostream &os,
bool value) {
764 os << (value ?
"true" :
"false");
771 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
772 static void printElement(raw_ostream &os, int8_t value) {
773 os << static_cast<int>(value);
777 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
779 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
781 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
785 struct DenseArrayAttrUtil<float> {
786 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
788 static void printElement(raw_ostream &os,
float value) { os << value; }
791 static ParseResult parseElement(
AsmParser &parser,
float &value) {
802 struct DenseArrayAttrUtil<double> {
803 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
805 static void printElement(raw_ostream &os,
float value) { os << value; }
806 static ParseResult parseElement(
AsmParser &parser,
double &value) {
812 template <
typename T>
817 template <
typename T>
819 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
820 DenseArrayAttrUtil<T>::printElement(os, value);
824 template <
typename T>
827 printWithoutBraces(os);
832 template <
typename T>
838 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
840 data.push_back(value);
848 template <
typename T>
855 Attribute result = parseWithoutBraces(parser, odsType);
862 template <
typename T>
865 assert((raw.size() %
sizeof(T)) == 0);
866 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
867 raw.size() /
sizeof(T));
871 template <
typename T>
875 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
876 content.size() *
sizeof(T));
877 return llvm::cast<DenseArrayAttrImpl<T>>(
878 Base::get(context, elementType, content.size(), rawArray));
881 template <
typename T>
883 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
884 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
907 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
914 Type eltType = type.getElementType();
917 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
918 if (complexType.getElementType().isIntOrIndex()) {
920 complexValues.reserve(values.size());
922 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
923 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
924 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
925 auto attr0 = arrayAttr[0];
926 auto attr1 = arrayAttr[1];
927 complexValues.push_back(
928 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
929 llvm::cast<IntegerAttr>(attr1).getValue()));
935 complexValues.reserve(values.size());
937 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
938 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
939 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
940 auto attr0 = arrayAttr[0];
941 auto attr1 = arrayAttr[1];
942 complexValues.push_back(
943 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
944 llvm::cast<FloatAttr>(attr1).getValue()));
953 stringValues.reserve(values.size());
955 assert(llvm::isa<StringAttr>(attr) &&
956 "expected string value for non integer/index/float element");
957 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
959 return get(type, stringValues);
970 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
971 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
972 assert(floatAttr.getType() == eltType &&
973 "expected float attribute type to equal element type");
974 intVal = floatAttr.getValue().bitcastToAPInt();
976 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
977 assert(intAttr.getType() == eltType &&
978 "expected integer attribute type to equal element type");
979 intVal = intAttr.getValue();
982 assert(intVal.getBitWidth() == bitWidth &&
983 "expected value to have same bitwidth as element type");
984 writeBits(data.data(), i * storageBitWidth, intVal);
988 if (values.size() == 1 && eltType.
isInteger(1))
989 data[0] = data[0] ? -1 : 0;
991 return DenseIntOrFPElementsAttr::getRaw(type, data);
997 assert(type.getElementType().isInteger(1));
1001 if (!values.empty()) {
1003 bool firstValue = values[0];
1004 for (
int i = 0, e = values.size(); i != e; ++i) {
1005 isSplat &= values[i] == firstValue;
1006 setBit(buff.data(), i, values[i]);
1012 buff[0] = values[0] ? -1 : 0;
1016 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1021 assert(!type.getElementType().isIntOrFloat());
1030 assert(type.getElementType().isIntOrIndex());
1033 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1036 ArrayRef<std::complex<APInt>> values) {
1037 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1038 assert(llvm::isa<IntegerType>(complex.getElementType()));
1041 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1043 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1051 assert(llvm::isa<FloatType>(type.getElementType()));
1054 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1058 ArrayRef<std::complex<APFloat>> values) {
1059 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1060 assert(llvm::isa<FloatType>(complex.getElementType()));
1065 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1073 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1079 bool &detectedSplat) {
1081 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1082 int64_t numElements = type.getNumElements();
1085 detectedSplat = numElements == 1;
1088 if (storageWidth == 1) {
1091 if (rawBuffer.size() == 1) {
1092 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1093 if (rawByte == 0 || rawByte == 0xff) {
1094 detectedSplat =
true;
1100 return rawBufferWidth == llvm::alignTo<8>(numElements);
1105 if (rawBufferWidth == storageWidth) {
1106 detectedSplat =
true;
1111 return rawBufferWidth == storageWidth * numElements;
1121 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1122 if (denseEltBitWidth != dataSize) {
1123 LDBG() <<
"expected dense element bit width " << denseEltBitWidth
1124 <<
" to match data size " << dataSize <<
" for type " << type;
1130 bool valid = llvm::isa<FloatType>(type);
1132 LDBG() <<
"expected float type when isInt is false, but found " << type;
1138 auto intType = llvm::dyn_cast<IntegerType>(type);
1140 LDBG() <<
"expected integer type when isInt is true, but found " << type;
1145 if (intType.isSignless())
1148 bool valid = intType.isSigned() == isSigned;
1150 LDBG() <<
"expected signedness " << isSigned <<
" to match type " << type;
1157 int64_t dataEltSize,
1158 bool isInt,
bool isSigned) {
1159 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1164 int64_t dataEltSize,
1167 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1172 bool isSigned)
const {
1176 bool isSigned)
const {
1179 dataEltSize / 2, isInt, isSigned);
1190 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1207 const auto &elementSemantics = eltTy.getFloatSemantics();
1218 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1221 const auto &semantics = eltTy.getFloatSemantics();
1223 getType(), {semantics, {*
this, 0}},
1240 ShapedType curType =
getType();
1241 if (curType == newType)
1244 assert(newType.getElementType() == curType.getElementType() &&
1245 "expected the same element type");
1246 assert(newType.getNumElements() == curType.getNumElements() &&
1247 "expected the same number of elements");
1248 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1252 assert(
isSplat() &&
"expected a splat type");
1254 ShapedType curType =
getType();
1255 if (curType == newType)
1258 assert(newType.getElementType() == curType.getElementType() &&
1259 "expected the same element type");
1260 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1268 ShapedType curType =
getType();
1269 Type curElType = curType.getElementType();
1270 if (curElType == newElType)
1275 "expected element types with the same bitwidth");
1276 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1283 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1289 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1298 return getType().getElementType();
1302 return getType().getNumElements();
1310 template <
typename APRangeT>
1313 APRangeT &&values) {
1314 size_t numValues = llvm::size(values);
1317 for (
auto it = values.begin(), e = values.end(); it != e;
1318 ++it, offset += storageWidth) {
1319 assert((*it).getBitWidth() <= storageWidth);
1324 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1325 data[0] = data[0] ? -1 : 0;
1332 size_t storageWidth,
1335 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1337 return DenseIntOrFPElementsAttr::getRaw(type, data);
1344 size_t storageWidth,
1348 return DenseIntOrFPElementsAttr::getRaw(type, data);
1353 assert(type.hasStaticShape() &&
"type must have static shape");
1366 int64_t dataEltSize,
1370 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1371 dataEltSize / 2, isInt, isSigned) &&
1372 "Try re-running with -debug-only=builtinattributes");
1374 int64_t numElements = data.size() / dataEltSize;
1376 assert(numElements == 1 || numElements == type.getNumElements());
1377 return getRaw(type, data);
1384 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1385 int64_t dataEltSize,
bool isInt,
1389 "Try re-running with -debug-only=builtinattributes");
1391 int64_t numElements = data.size() / dataEltSize;
1392 assert(numElements == 1 || numElements == type.getNumElements());
1394 return getRaw(type, data);
1397 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1398 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1399 size_t numElements) {
1400 using llvm::support::ulittle16_t;
1401 using llvm::support::ulittle32_t;
1402 using llvm::support::ulittle64_t;
1404 assert(llvm::endianness::native == llvm::endianness::big);
1408 switch (elementBitWidth) {
1410 const ulittle16_t *inRawDataPos =
1411 reinterpret_cast<const ulittle16_t *
>(inRawData);
1412 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1413 std::copy_n(inRawDataPos, numElements, outDataPos);
1417 const ulittle32_t *inRawDataPos =
1418 reinterpret_cast<const ulittle32_t *
>(inRawData);
1419 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1420 std::copy_n(inRawDataPos, numElements, outDataPos);
1424 const ulittle64_t *inRawDataPos =
1425 reinterpret_cast<const ulittle64_t *
>(inRawData);
1426 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1427 std::copy_n(inRawDataPos, numElements, outDataPos);
1431 size_t nBytes = elementBitWidth / CHAR_BIT;
1432 for (
size_t i = 0; i < nBytes; i++)
1433 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1439 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1442 size_t numElements = type.getNumElements();
1443 Type elementType = type.getElementType();
1444 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1445 elementType = complexTy.getElementType();
1446 numElements = numElements * 2;
1449 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1450 inRawData.size() <= outRawData.size());
1451 if (elementBitWidth <= CHAR_BIT)
1452 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1454 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1455 elementBitWidth, numElements);
1462 template <
typename Fn,
typename Attr>
1464 Type newElementType,
1469 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1471 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1475 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1476 auto newInt = mapping(value);
1477 assert(newInt.getBitWidth() == bitWidth);
1478 writeBits(data.data(), index * storageBitWidth, newInt);
1482 if (attr.isSplat()) {
1483 if (bitWidth == 1) {
1485 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1487 processElt(*attr.begin(), 0);
1489 return newArrayType;
1493 uint64_t elementIdx = 0;
1494 for (
auto value : attr)
1495 processElt(value, elementIdx++);
1496 return newArrayType;
1505 return getRaw(newArrayType, elementData);
1510 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1511 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1524 return getRaw(newArrayType, elementData);
1529 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1530 return denseAttr.getType().getElementType().isIntOrIndex();
1541 return Base::get(type.getContext(), type, handle);
1551 return get(type, manager.insert(blobName, std::move(blob)));
1556 return blob->getDataAs<
char>();
1567 template <
typename T>
1568 struct DenseResourceAttrUtil;
1569 template <
size_t w
idth,
bool isSigned>
1570 struct DenseResourceElementsAttrIntUtil {
1571 static bool checkElementType(
Type eltType) {
1572 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1573 if (!type || type.getWidth() != width)
1575 return isSigned ? !type.isUnsigned() : !type.isSigned();
1579 struct DenseResourceAttrUtil<bool> {
1580 static bool checkElementType(
Type eltType) {
1585 struct DenseResourceAttrUtil<int8_t>
1586 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1588 struct DenseResourceAttrUtil<uint8_t>
1589 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1591 struct DenseResourceAttrUtil<int16_t>
1592 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1594 struct DenseResourceAttrUtil<uint16_t>
1595 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1597 struct DenseResourceAttrUtil<int32_t>
1598 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1600 struct DenseResourceAttrUtil<uint32_t>
1601 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1603 struct DenseResourceAttrUtil<int64_t>
1604 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1606 struct DenseResourceAttrUtil<uint64_t>
1607 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1609 struct DenseResourceAttrUtil<float> {
1610 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1613 struct DenseResourceAttrUtil<double> {
1614 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1618 template <
typename T>
1624 "alignment mismatch between expected alignment and blob alignment");
1625 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1626 "size mismatch between expected element width and blob size");
1627 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1628 "invalid shape element type for provided type `T`");
1629 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1633 template <
typename T>
1634 std::optional<ArrayRef<T>>
1637 return blob->template getDataAs<T>();
1638 return std::nullopt;
1641 template <
typename T>
1643 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1644 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1645 resourceAttr.getElementType());
1670 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1672 return APFloat(eltType.getFloatSemantics());
1676 APInt SparseElementsAttr::getZeroAPInt()
const {
1682 Attribute SparseElementsAttr::getZeroAttr()
const {
1686 if (llvm::isa<FloatType>(eltType))
1690 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1691 auto eltType = complexTy.getElementType();
1693 if (llvm::isa<FloatType>(eltType))
1702 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1717 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1718 if (sparseIndices.isSplat()) {
1720 *sparseIndexValues.begin());
1721 flatSparseIndices.push_back(getFlattenedIndex(indices));
1722 return flatSparseIndices;
1726 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1727 size_t rank =
getType().getRank();
1728 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1729 flatSparseIndices.push_back(getFlattenedIndex(
1730 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1731 return flatSparseIndices;
1738 ShapedType valuesType = values.
getType();
1739 if (valuesType.getRank() != 1)
1740 return emitError() <<
"expected 1-d tensor for sparse element values";
1743 ShapedType indicesType = sparseIndices.getType();
1744 auto emitShapeError = [&]() {
1745 return emitError() <<
"expected shape ([" << type.getShape()
1746 <<
"]); inferred shape of indices literal (["
1747 << indicesType.getShape()
1748 <<
"]); inferred shape of values literal (["
1749 << valuesType.getShape() <<
"])";
1752 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1753 if (indicesRank == 2) {
1754 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1755 return emitShapeError();
1756 }
else if (indicesRank != 1 || rank != 1) {
1757 return emitShapeError();
1760 int64_t numSparseIndices = indicesType.getDimSize(0);
1761 if (numSparseIndices != valuesType.getDimSize(0))
1762 return emitShapeError();
1767 <<
"sparse index #" << indexNum
1768 <<
" is not contained within the value shape, with index=[" << index
1769 <<
"], and type=" << type;
1773 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1774 if (sparseIndices.isSplat()) {
1776 if (!ElementsAttr::isValidIndex(type, indices))
1777 return emitIndexError(0, indices);
1782 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1785 if (!ElementsAttr::isValidIndex(type, index))
1786 return emitIndexError(i, index);
1801 return getImpl()->referencedAttr;
1812 unsigned nSymbols = 0;
1816 if (ShapedType::isStatic(offset)) {
1827 auto dim = en.index();
1828 auto stride = en.value();
1832 if (ShapedType::isStatic(stride))
1837 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 Type getElementType(Type type)
Determine the element type of type.
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static DimensionSize operator*(DimensionSize lhs, DimensionSize rhs)
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.