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());
234 bool StridedLayoutAttr::hasStaticLayout()
const {
235 return !ShapedType::isDynamic(getOffset()) &&
236 !ShapedType::isDynamicShape(getStrides());
240 AffineMap StridedLayoutAttr::getAffineMap()
const {
252 LogicalResult StridedLayoutAttr::verifyLayout(
255 if (shape.size() != getStrides().size())
256 return emitError() <<
"expected the number of strides to match the rank";
265 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
272 if (twine.isTriviallyEmpty())
284 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
288 Dialect *StringAttr::getReferencedDialect()
const {
289 return getImpl()->referencedDialect;
296 double FloatAttr::getValueAsDouble()
const {
297 return getValueAsDouble(getValue());
299 double FloatAttr::getValueAsDouble(APFloat value) {
300 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
301 bool losesInfo =
false;
302 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
305 return value.convertToDouble();
309 Type type, APFloat value) {
311 if (!llvm::isa<FloatType>(type))
312 return emitError() <<
"expected floating point type";
315 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
316 &value.getSemantics()) {
318 <<
"FloatAttr type doesn't match the type implied by its value";
333 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
337 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
343 assert(symName &&
"value does not have a valid symbol name");
347 StringAttr SymbolRefAttr::getLeafReference()
const {
349 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
356 int64_t IntegerAttr::getInt()
const {
358 "must be signless integer");
359 return getValue().getSExtValue();
362 int64_t IntegerAttr::getSInt()
const {
363 assert(
getType().isSignedInteger() &&
"must be signed integer");
364 return getValue().getSExtValue();
367 uint64_t IntegerAttr::getUInt()
const {
368 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
369 return getValue().getZExtValue();
374 APSInt IntegerAttr::getAPSInt()
const {
375 assert(!
getType().isSignlessInteger() &&
376 "Signless integers don't carry a sign for APSInt");
377 return APSInt(getValue(),
getType().isUnsignedInteger());
381 Type type, APInt value) {
382 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
383 if (integerType.getWidth() != value.getBitWidth())
384 return emitError() <<
"integer type bit width (" << integerType.getWidth()
385 <<
") doesn't match value bit width ("
386 << value.getBitWidth() <<
")";
389 if (llvm::isa<IndexType>(type)) {
390 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
392 <<
"value bit width (" << value.getBitWidth()
393 <<
") doesn't match index type internal storage bit width ("
394 << IndexType::kInternalStorageBitWidth <<
")";
397 return emitError() <<
"expected integer or index type";
400 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
401 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
402 return llvm::cast<BoolAttr>(attr);
410 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
411 return storage->value.getBoolValue();
415 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
416 return intAttr && intAttr.getType().isSignlessInteger(1);
424 StringAttr dialect, StringRef attrData,
427 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
434 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
435 <<
" attribute created with unregistered dialect. If this is "
436 "intended, please call allowUnregisteredDialects() on the "
437 "MLIRContext, or use -allow-unregistered-dialect with "
438 "the MLIR opt tool used";
454 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
461 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
463 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
465 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
469 static bool getBit(
const char *rawData,
size_t bitPos) {
470 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
477 assert(llvm::endianness::native == llvm::endianness::big);
478 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
483 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
484 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
485 numFilledWords, result);
489 size_t lastWordPos = numFilledWords;
491 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
492 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
493 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
497 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
498 valueLE.begin(), result + lastWordPos,
499 (numBytes - lastWordPos) * CHAR_BIT, 1);
506 assert(llvm::endianness::native == llvm::endianness::big);
507 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
514 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
516 inArray, numFilledWords,
517 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
522 size_t lastWordPos = numFilledWords;
524 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
525 inArray + lastWordPos, inArrayLE.begin(),
526 (numBytes - lastWordPos) * CHAR_BIT, 1);
530 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
532 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
534 APInt::APINT_BITS_PER_WORD, 1);
538 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
539 size_t bitWidth = value.getBitWidth();
543 return setBit(rawData, bitPos, value.isOne());
546 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
547 if (llvm::endianness::native == llvm::endianness::big) {
554 rawData + (bitPos / CHAR_BIT));
556 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
558 rawData + (bitPos / CHAR_BIT));
564 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
567 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
570 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
571 APInt result(bitWidth, 0);
572 if (llvm::endianness::native == llvm::endianness::big) {
581 std::copy_n(rawData + (bitPos / CHAR_BIT),
584 reinterpret_cast<const char *
>(result.getRawData())));
591 template <
typename Values>
593 return (values.size() == 1) ||
594 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
605 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
607 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
609 attr.getAsOpaquePointer(), index) {}
613 Type eltTy = owner.getElementType();
614 if (llvm::dyn_cast<IntegerType>(eltTy))
616 if (llvm::isa<IndexType>(eltTy))
618 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
623 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
624 auto complexEltTy = complexTy.getElementType();
626 if (llvm::isa<IntegerType>(complexEltTy)) {
627 auto value = *complexIntIt;
635 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
636 auto value = *complexFloatIt;
642 if (llvm::isa<DenseStringElementsAttr>(owner)) {
644 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
646 llvm_unreachable(
"unexpected element type");
653 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
659 return getBit(getData(), getDataIndex());
666 DenseElementsAttr::IntElementIterator::IntElementIterator(
682 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
685 std::complex<APInt>, std::complex<APInt>,
686 std::complex<APInt>>(
688 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
695 size_t offset = getDataIndex() * storageWidth * 2;
696 return {
readBits(getData(), offset, bitWidth),
697 readBits(getData(), offset + storageWidth, bitWidth)};
708 return emitError() <<
"expected integer or floating point element type";
709 int64_t dataSize = rawData.size();
710 int64_t elementSize =
712 if (
size * elementSize != dataSize) {
713 return emitError() <<
"expected data size (" <<
size <<
" elements, "
715 <<
" bytes each) does not match: " << dataSize
724 template <
size_t width,
725 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
726 struct DenseArrayAttrIntUtil {
727 static bool checkElementType(
Type eltType) {
728 auto type = llvm::dyn_cast<IntegerType>(eltType);
729 if (!type || type.getWidth() != width)
731 return type.getSignedness() == signedness;
738 template <
typename T>
739 static void printElement(raw_ostream &os, T value) {
743 template <
typename T>
744 static ParseResult parseElement(
AsmParser &parser, T &value) {
748 template <
typename T>
749 struct DenseArrayAttrUtil;
754 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
755 static void printElement(raw_ostream &os,
bool value) {
756 os << (value ?
"true" :
"false");
763 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
764 static void printElement(raw_ostream &os, int8_t value) {
765 os << static_cast<int>(value);
769 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
771 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
773 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
777 struct DenseArrayAttrUtil<float> {
778 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
780 static void printElement(raw_ostream &os,
float value) { os << value; }
783 static ParseResult parseElement(
AsmParser &parser,
float &value) {
794 struct DenseArrayAttrUtil<double> {
795 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
797 static void printElement(raw_ostream &os,
float value) { os << value; }
798 static ParseResult parseElement(
AsmParser &parser,
double &value) {
804 template <
typename T>
809 template <
typename T>
811 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
812 DenseArrayAttrUtil<T>::printElement(os, value);
816 template <
typename T>
819 printWithoutBraces(os);
824 template <
typename T>
830 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
832 data.push_back(value);
840 template <
typename T>
847 Attribute result = parseWithoutBraces(parser, odsType);
854 template <
typename T>
857 assert((raw.size() %
sizeof(T)) == 0);
858 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
859 raw.size() /
sizeof(T));
863 template <
typename T>
867 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
868 content.size() *
sizeof(T));
869 return llvm::cast<DenseArrayAttrImpl<T>>(
870 Base::get(context, elementType, content.size(), rawArray));
873 template <
typename T>
875 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
876 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
899 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
906 Type eltType = type.getElementType();
909 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
910 if (complexType.getElementType().isIntOrIndex()) {
912 complexValues.reserve(values.size());
914 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
915 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
916 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
917 auto attr0 = arrayAttr[0];
918 auto attr1 = arrayAttr[1];
919 complexValues.push_back(
920 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
921 llvm::cast<IntegerAttr>(attr1).getValue()));
927 complexValues.reserve(values.size());
929 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
930 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
931 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
932 auto attr0 = arrayAttr[0];
933 auto attr1 = arrayAttr[1];
934 complexValues.push_back(
935 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
936 llvm::cast<FloatAttr>(attr1).getValue()));
945 stringValues.reserve(values.size());
947 assert(llvm::isa<StringAttr>(attr) &&
948 "expected string value for non integer/index/float element");
949 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
951 return get(type, stringValues);
962 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
963 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
964 assert(floatAttr.getType() == eltType &&
965 "expected float attribute type to equal element type");
966 intVal = floatAttr.getValue().bitcastToAPInt();
968 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
969 assert(intAttr.getType() == eltType &&
970 "expected integer attribute type to equal element type");
971 intVal = intAttr.getValue();
974 assert(intVal.getBitWidth() == bitWidth &&
975 "expected value to have same bitwidth as element type");
976 writeBits(data.data(), i * storageBitWidth, intVal);
980 if (values.size() == 1 && eltType.
isInteger(1))
981 data[0] = data[0] ? -1 : 0;
983 return DenseIntOrFPElementsAttr::getRaw(type, data);
989 assert(type.getElementType().isInteger(1));
993 if (!values.empty()) {
995 bool firstValue = values[0];
996 for (
int i = 0, e = values.size(); i != e; ++i) {
997 isSplat &= values[i] == firstValue;
998 setBit(buff.data(), i, values[i]);
1004 buff[0] = values[0] ? -1 : 0;
1008 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1013 assert(!type.getElementType().isIntOrFloat());
1022 assert(type.getElementType().isIntOrIndex());
1025 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1028 ArrayRef<std::complex<APInt>> values) {
1029 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1030 assert(llvm::isa<IntegerType>(complex.getElementType()));
1033 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1035 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1043 assert(llvm::isa<FloatType>(type.getElementType()));
1046 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1050 ArrayRef<std::complex<APFloat>> values) {
1051 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1052 assert(llvm::isa<FloatType>(complex.getElementType()));
1057 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1065 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1071 bool &detectedSplat) {
1073 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1074 int64_t numElements = type.getNumElements();
1077 detectedSplat = numElements == 1;
1080 if (storageWidth == 1) {
1083 if (rawBuffer.size() == 1) {
1084 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1085 if (rawByte == 0 || rawByte == 0xff) {
1086 detectedSplat =
true;
1092 return rawBufferWidth == llvm::alignTo<8>(numElements);
1097 if (rawBufferWidth == storageWidth) {
1098 detectedSplat =
true;
1103 return rawBufferWidth == storageWidth * numElements;
1113 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1114 if (denseEltBitWidth != dataSize) {
1115 LLVM_DEBUG(llvm::dbgs() <<
"expected dense element bit width "
1116 << denseEltBitWidth <<
" to match data size "
1117 << dataSize <<
" for type " << type <<
"\n");
1123 bool valid = llvm::isa<FloatType>(type);
1125 LLVM_DEBUG(llvm::dbgs()
1126 <<
"expected float type when isInt is false, but found "
1133 auto intType = llvm::dyn_cast<IntegerType>(type);
1135 LLVM_DEBUG(llvm::dbgs()
1136 <<
"expected integer type when isInt is true, but found " << type
1142 if (intType.isSignless())
1145 bool valid = intType.isSigned() == isSigned;
1147 LLVM_DEBUG(llvm::dbgs() <<
"expected signedness " << isSigned
1148 <<
" to match type " << type <<
"\n");
1155 int64_t dataEltSize,
1156 bool isInt,
bool isSigned) {
1157 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1162 int64_t dataEltSize,
1165 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1170 bool isSigned)
const {
1174 bool isSigned)
const {
1177 dataEltSize / 2, isInt, isSigned);
1188 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1205 const auto &elementSemantics = eltTy.getFloatSemantics();
1216 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1219 const auto &semantics = eltTy.getFloatSemantics();
1221 getType(), {semantics, {*
this, 0}},
1238 ShapedType curType =
getType();
1239 if (curType == newType)
1242 assert(newType.getElementType() == curType.getElementType() &&
1243 "expected the same element type");
1244 assert(newType.getNumElements() == curType.getNumElements() &&
1245 "expected the same number of elements");
1246 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1250 assert(
isSplat() &&
"expected a splat type");
1252 ShapedType curType =
getType();
1253 if (curType == newType)
1256 assert(newType.getElementType() == curType.getElementType() &&
1257 "expected the same element type");
1258 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1266 ShapedType curType =
getType();
1267 Type curElType = curType.getElementType();
1268 if (curElType == newElType)
1273 "expected element types with the same bitwidth");
1274 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1281 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1287 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1296 return getType().getElementType();
1300 return getType().getNumElements();
1308 template <
typename APRangeT>
1310 APRangeT &&values) {
1311 size_t numValues = llvm::size(values);
1314 for (
auto it = values.begin(), e = values.end(); it != e;
1315 ++it, offset += storageWidth) {
1316 assert((*it).getBitWidth() <= storageWidth);
1321 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1322 data[0] = data[0] ? -1 : 0;
1329 size_t storageWidth,
1331 std::vector<char> data;
1332 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1334 return DenseIntOrFPElementsAttr::getRaw(type, data);
1341 size_t storageWidth,
1343 std::vector<char> data;
1345 return DenseIntOrFPElementsAttr::getRaw(type, data);
1350 assert(type.hasStaticShape() &&
"type must have static shape");
1363 int64_t dataEltSize,
1367 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1368 dataEltSize / 2, isInt, isSigned) &&
1369 "Try re-running with -debug-only=builtinattributes");
1371 int64_t numElements = data.size() / dataEltSize;
1373 assert(numElements == 1 || numElements == type.getNumElements());
1374 return getRaw(type, data);
1381 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1382 int64_t dataEltSize,
bool isInt,
1386 "Try re-running with -debug-only=builtinattributes");
1388 int64_t numElements = data.size() / dataEltSize;
1389 assert(numElements == 1 || numElements == type.getNumElements());
1391 return getRaw(type, data);
1394 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1395 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1396 size_t numElements) {
1397 using llvm::support::ulittle16_t;
1398 using llvm::support::ulittle32_t;
1399 using llvm::support::ulittle64_t;
1401 assert(llvm::endianness::native == llvm::endianness::big);
1405 switch (elementBitWidth) {
1407 const ulittle16_t *inRawDataPos =
1408 reinterpret_cast<const ulittle16_t *
>(inRawData);
1409 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1410 std::copy_n(inRawDataPos, numElements, outDataPos);
1414 const ulittle32_t *inRawDataPos =
1415 reinterpret_cast<const ulittle32_t *
>(inRawData);
1416 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1417 std::copy_n(inRawDataPos, numElements, outDataPos);
1421 const ulittle64_t *inRawDataPos =
1422 reinterpret_cast<const ulittle64_t *
>(inRawData);
1423 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1424 std::copy_n(inRawDataPos, numElements, outDataPos);
1428 size_t nBytes = elementBitWidth / CHAR_BIT;
1429 for (
size_t i = 0; i < nBytes; i++)
1430 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1436 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1439 size_t numElements = type.getNumElements();
1440 Type elementType = type.getElementType();
1441 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1442 elementType = complexTy.getElementType();
1443 numElements = numElements * 2;
1446 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1447 inRawData.size() <= outRawData.size());
1448 if (elementBitWidth <= CHAR_BIT)
1449 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1451 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1452 elementBitWidth, numElements);
1459 template <
typename Fn,
typename Attr>
1461 Type newElementType,
1466 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1468 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1472 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1473 auto newInt = mapping(value);
1474 assert(newInt.getBitWidth() == bitWidth);
1475 writeBits(data.data(), index * storageBitWidth, newInt);
1479 if (attr.isSplat()) {
1480 if (bitWidth == 1) {
1482 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1484 processElt(*attr.begin(), 0);
1486 return newArrayType;
1490 uint64_t elementIdx = 0;
1491 for (
auto value : attr)
1492 processElt(value, elementIdx++);
1493 return newArrayType;
1502 return getRaw(newArrayType, elementData);
1507 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1508 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1521 return getRaw(newArrayType, elementData);
1526 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1527 return denseAttr.getType().getElementType().isIntOrIndex();
1538 return Base::get(type.getContext(), type, handle);
1548 return get(type, manager.insert(blobName, std::move(blob)));
1553 return blob->getDataAs<
char>();
1564 template <
typename T>
1565 struct DenseResourceAttrUtil;
1566 template <
size_t w
idth,
bool isSigned>
1567 struct DenseResourceElementsAttrIntUtil {
1568 static bool checkElementType(
Type eltType) {
1569 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1570 if (!type || type.getWidth() != width)
1572 return isSigned ? !type.isUnsigned() : !type.isSigned();
1576 struct DenseResourceAttrUtil<bool> {
1577 static bool checkElementType(
Type eltType) {
1582 struct DenseResourceAttrUtil<int8_t>
1583 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1585 struct DenseResourceAttrUtil<uint8_t>
1586 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1588 struct DenseResourceAttrUtil<int16_t>
1589 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1591 struct DenseResourceAttrUtil<uint16_t>
1592 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1594 struct DenseResourceAttrUtil<int32_t>
1595 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1597 struct DenseResourceAttrUtil<uint32_t>
1598 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1600 struct DenseResourceAttrUtil<int64_t>
1601 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1603 struct DenseResourceAttrUtil<uint64_t>
1604 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1606 struct DenseResourceAttrUtil<float> {
1607 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1610 struct DenseResourceAttrUtil<double> {
1611 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1615 template <
typename T>
1621 "alignment mismatch between expected alignment and blob alignment");
1622 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1623 "size mismatch between expected element width and blob size");
1624 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1625 "invalid shape element type for provided type `T`");
1626 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1630 template <
typename T>
1631 std::optional<ArrayRef<T>>
1634 return blob->template getDataAs<T>();
1635 return std::nullopt;
1638 template <
typename T>
1640 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1641 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1642 resourceAttr.getElementType());
1667 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1669 return APFloat(eltType.getFloatSemantics());
1673 APInt SparseElementsAttr::getZeroAPInt()
const {
1679 Attribute SparseElementsAttr::getZeroAttr()
const {
1683 if (llvm::isa<FloatType>(eltType))
1687 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1688 auto eltType = complexTy.getElementType();
1690 if (llvm::isa<FloatType>(eltType))
1699 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1708 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1709 std::vector<ptrdiff_t> flatSparseIndices;
1714 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1715 if (sparseIndices.isSplat()) {
1717 *sparseIndexValues.begin());
1718 flatSparseIndices.push_back(getFlattenedIndex(indices));
1719 return flatSparseIndices;
1723 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1724 size_t rank =
getType().getRank();
1725 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1726 flatSparseIndices.push_back(getFlattenedIndex(
1727 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1728 return flatSparseIndices;
1735 ShapedType valuesType = values.
getType();
1736 if (valuesType.getRank() != 1)
1737 return emitError() <<
"expected 1-d tensor for sparse element values";
1740 ShapedType indicesType = sparseIndices.getType();
1741 auto emitShapeError = [&]() {
1742 return emitError() <<
"expected shape ([" << type.getShape()
1743 <<
"]); inferred shape of indices literal (["
1744 << indicesType.getShape()
1745 <<
"]); inferred shape of values literal (["
1746 << valuesType.getShape() <<
"])";
1749 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1750 if (indicesRank == 2) {
1751 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1752 return emitShapeError();
1753 }
else if (indicesRank != 1 || rank != 1) {
1754 return emitShapeError();
1757 int64_t numSparseIndices = indicesType.getDimSize(0);
1758 if (numSparseIndices != valuesType.getDimSize(0))
1759 return emitShapeError();
1764 <<
"sparse index #" << indexNum
1765 <<
" is not contained within the value shape, with index=[" << index
1766 <<
"], and type=" << type;
1770 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1771 if (sparseIndices.isSplat()) {
1773 if (!ElementsAttr::isValidIndex(type, indices))
1774 return emitIndexError(0, indices);
1779 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1782 if (!ElementsAttr::isValidIndex(type, index))
1783 return emitIndexError(i, index);
1798 return getImpl()->referencedAttr;
1809 unsigned nSymbols = 0;
1813 if (!ShapedType::isDynamic(offset)) {
1824 auto dim = en.index();
1825 auto stride = en.value();
1829 if (!ShapedType::isDynamic(stride))
1834 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.
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.