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 {
248 if (llvm::is_contained(strides, 0))
249 return emitError() <<
"strides must not be zero";
255 LogicalResult StridedLayoutAttr::verifyLayout(
258 if (shape.size() != getStrides().size())
259 return emitError() <<
"expected the number of strides to match the rank";
268 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
275 if (twine.isTriviallyEmpty())
287 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
291 Dialect *StringAttr::getReferencedDialect()
const {
292 return getImpl()->referencedDialect;
299 double FloatAttr::getValueAsDouble()
const {
300 return getValueAsDouble(getValue());
302 double FloatAttr::getValueAsDouble(APFloat value) {
303 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
304 bool losesInfo =
false;
305 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
308 return value.convertToDouble();
312 Type type, APFloat value) {
314 if (!llvm::isa<FloatType>(type))
315 return emitError() <<
"expected floating point type";
318 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
319 &value.getSemantics()) {
321 <<
"FloatAttr type doesn't match the type implied by its value";
336 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
340 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
346 assert(symName &&
"value does not have a valid symbol name");
350 StringAttr SymbolRefAttr::getLeafReference()
const {
352 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
359 int64_t IntegerAttr::getInt()
const {
361 "must be signless integer");
362 return getValue().getSExtValue();
365 int64_t IntegerAttr::getSInt()
const {
366 assert(
getType().isSignedInteger() &&
"must be signed integer");
367 return getValue().getSExtValue();
370 uint64_t IntegerAttr::getUInt()
const {
371 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
372 return getValue().getZExtValue();
377 APSInt IntegerAttr::getAPSInt()
const {
378 assert(!
getType().isSignlessInteger() &&
379 "Signless integers don't carry a sign for APSInt");
380 return APSInt(getValue(),
getType().isUnsignedInteger());
384 Type type, APInt value) {
385 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
386 if (integerType.getWidth() != value.getBitWidth())
387 return emitError() <<
"integer type bit width (" << integerType.getWidth()
388 <<
") doesn't match value bit width ("
389 << value.getBitWidth() <<
")";
392 if (llvm::isa<IndexType>(type)) {
393 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
395 <<
"value bit width (" << value.getBitWidth()
396 <<
") doesn't match index type internal storage bit width ("
397 << IndexType::kInternalStorageBitWidth <<
")";
400 return emitError() <<
"expected integer or index type";
403 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
404 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
405 return llvm::cast<BoolAttr>(attr);
413 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
414 return storage->value.getBoolValue();
418 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
419 return intAttr && intAttr.getType().isSignlessInteger(1);
427 StringAttr dialect, StringRef attrData,
430 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
437 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
438 <<
" attribute created with unregistered dialect. If this is "
439 "intended, please call allowUnregisteredDialects() on the "
440 "MLIRContext, or use -allow-unregistered-dialect with "
441 "the MLIR opt tool used";
457 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
464 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
466 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
468 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
472 static bool getBit(
const char *rawData,
size_t bitPos) {
473 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
480 assert(llvm::endianness::native == llvm::endianness::big);
481 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
486 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
487 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
488 numFilledWords, result);
492 size_t lastWordPos = numFilledWords;
494 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
495 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
496 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
500 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
501 valueLE.begin(), result + lastWordPos,
502 (numBytes - lastWordPos) * CHAR_BIT, 1);
509 assert(llvm::endianness::native == llvm::endianness::big);
510 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
517 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
519 inArray, numFilledWords,
520 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
525 size_t lastWordPos = numFilledWords;
527 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
528 inArray + lastWordPos, inArrayLE.begin(),
529 (numBytes - lastWordPos) * CHAR_BIT, 1);
533 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
535 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
537 APInt::APINT_BITS_PER_WORD, 1);
541 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
542 size_t bitWidth = value.getBitWidth();
546 return setBit(rawData, bitPos, value.isOne());
549 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
550 if (llvm::endianness::native == llvm::endianness::big) {
557 rawData + (bitPos / CHAR_BIT));
559 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
561 rawData + (bitPos / CHAR_BIT));
567 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
570 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
573 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
574 APInt result(bitWidth, 0);
575 if (llvm::endianness::native == llvm::endianness::big) {
584 std::copy_n(rawData + (bitPos / CHAR_BIT),
587 reinterpret_cast<const char *
>(result.getRawData())));
594 template <
typename Values>
596 return (values.size() == 1) ||
597 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
607 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
609 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
611 attr.getAsOpaquePointer(), index) {}
615 Type eltTy = owner.getElementType();
616 if (llvm::dyn_cast<IntegerType>(eltTy))
618 if (llvm::isa<IndexType>(eltTy))
620 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
625 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
626 auto complexEltTy = complexTy.getElementType();
628 if (llvm::isa<IntegerType>(complexEltTy)) {
629 auto value = *complexIntIt;
637 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
638 auto value = *complexFloatIt;
644 if (llvm::isa<DenseStringElementsAttr>(owner)) {
646 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
648 llvm_unreachable(
"unexpected element type");
654 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
660 return getBit(getData(), getDataIndex());
666 DenseElementsAttr::IntElementIterator::IntElementIterator(
681 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
684 std::complex<APInt>, std::complex<APInt>,
685 std::complex<APInt>>(
687 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
694 size_t offset = getDataIndex() * storageWidth * 2;
695 return {
readBits(getData(), offset, bitWidth),
696 readBits(getData(), offset + storageWidth, bitWidth)};
707 return emitError() <<
"expected integer or floating point element type";
708 int64_t dataSize = rawData.size();
709 int64_t elementSize =
711 if (
size * elementSize != dataSize) {
712 return emitError() <<
"expected data size (" <<
size <<
" elements, "
714 <<
" bytes each) does not match: " << dataSize
723 template <
size_t width,
724 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
725 struct DenseArrayAttrIntUtil {
726 static bool checkElementType(
Type eltType) {
727 auto type = llvm::dyn_cast<IntegerType>(eltType);
728 if (!type || type.getWidth() != width)
730 return type.getSignedness() == signedness;
737 template <
typename T>
738 static void printElement(raw_ostream &os, T value) {
742 template <
typename T>
743 static ParseResult parseElement(
AsmParser &parser, T &value) {
747 template <
typename T>
748 struct DenseArrayAttrUtil;
753 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
754 static void printElement(raw_ostream &os,
bool value) {
755 os << (value ?
"true" :
"false");
762 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
763 static void printElement(raw_ostream &os, int8_t value) {
764 os << static_cast<int>(value);
768 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
770 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
772 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
776 struct DenseArrayAttrUtil<float> {
777 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
779 static void printElement(raw_ostream &os,
float value) { os << value; }
782 static ParseResult parseElement(
AsmParser &parser,
float &value) {
793 struct DenseArrayAttrUtil<double> {
794 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
796 static void printElement(raw_ostream &os,
float value) { os << value; }
797 static ParseResult parseElement(
AsmParser &parser,
double &value) {
803 template <
typename T>
808 template <
typename T>
810 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
811 DenseArrayAttrUtil<T>::printElement(os, value);
815 template <
typename T>
818 printWithoutBraces(os);
823 template <
typename T>
829 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
831 data.push_back(value);
839 template <
typename T>
846 Attribute result = parseWithoutBraces(parser, odsType);
853 template <
typename T>
856 assert((raw.size() %
sizeof(T)) == 0);
857 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
858 raw.size() /
sizeof(T));
862 template <
typename T>
866 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
867 content.size() *
sizeof(T));
868 return llvm::cast<DenseArrayAttrImpl<T>>(
869 Base::get(context, elementType, content.size(), rawArray));
872 template <
typename T>
874 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
875 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
898 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
905 Type eltType = type.getElementType();
908 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
909 if (complexType.getElementType().isIntOrIndex()) {
911 complexValues.reserve(values.size());
913 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
914 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
915 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
916 auto attr0 = arrayAttr[0];
917 auto attr1 = arrayAttr[1];
918 complexValues.push_back(
919 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
920 llvm::cast<IntegerAttr>(attr1).getValue()));
926 complexValues.reserve(values.size());
928 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
929 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
930 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
931 auto attr0 = arrayAttr[0];
932 auto attr1 = arrayAttr[1];
933 complexValues.push_back(
934 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
935 llvm::cast<FloatAttr>(attr1).getValue()));
944 stringValues.reserve(values.size());
946 assert(llvm::isa<StringAttr>(attr) &&
947 "expected string value for non integer/index/float element");
948 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
950 return get(type, stringValues);
961 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
962 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
963 assert(floatAttr.getType() == eltType &&
964 "expected float attribute type to equal element type");
965 intVal = floatAttr.getValue().bitcastToAPInt();
967 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
968 assert(intAttr.getType() == eltType &&
969 "expected integer attribute type to equal element type");
970 intVal = intAttr.getValue();
973 assert(intVal.getBitWidth() == bitWidth &&
974 "expected value to have same bitwidth as element type");
975 writeBits(data.data(), i * storageBitWidth, intVal);
979 if (values.size() == 1 && eltType.
isInteger(1))
980 data[0] = data[0] ? -1 : 0;
982 return DenseIntOrFPElementsAttr::getRaw(type, data);
988 assert(type.getElementType().isInteger(1));
992 if (!values.empty()) {
994 bool firstValue = values[0];
995 for (
int i = 0, e = values.size(); i != e; ++i) {
996 isSplat &= values[i] == firstValue;
997 setBit(buff.data(), i, values[i]);
1003 buff[0] = values[0] ? -1 : 0;
1007 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1012 assert(!type.getElementType().isIntOrFloat());
1021 assert(type.getElementType().isIntOrIndex());
1024 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1027 ArrayRef<std::complex<APInt>> values) {
1028 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1029 assert(llvm::isa<IntegerType>(complex.getElementType()));
1032 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1034 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1042 assert(llvm::isa<FloatType>(type.getElementType()));
1045 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1049 ArrayRef<std::complex<APFloat>> values) {
1050 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1051 assert(llvm::isa<FloatType>(complex.getElementType()));
1056 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1064 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1070 bool &detectedSplat) {
1072 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1073 int64_t numElements = type.getNumElements();
1076 detectedSplat = numElements == 1;
1079 if (storageWidth == 1) {
1082 if (rawBuffer.size() == 1) {
1083 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1084 if (rawByte == 0 || rawByte == 0xff) {
1085 detectedSplat =
true;
1091 return rawBufferWidth == llvm::alignTo<8>(numElements);
1096 if (rawBufferWidth == storageWidth) {
1097 detectedSplat =
true;
1102 return rawBufferWidth == storageWidth * numElements;
1112 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1113 if (denseEltBitWidth != dataSize) {
1114 LLVM_DEBUG(llvm::dbgs() <<
"expected dense element bit width "
1115 << denseEltBitWidth <<
" to match data size "
1116 << dataSize <<
" for type " << type <<
"\n");
1122 bool valid = llvm::isa<FloatType>(type);
1124 LLVM_DEBUG(llvm::dbgs()
1125 <<
"expected float type when isInt is false, but found "
1132 auto intType = llvm::dyn_cast<IntegerType>(type);
1134 LLVM_DEBUG(llvm::dbgs()
1135 <<
"expected integer type when isInt is true, but found " << type
1141 if (intType.isSignless())
1144 bool valid = intType.isSigned() == isSigned;
1146 LLVM_DEBUG(llvm::dbgs() <<
"expected signedness " << isSigned
1147 <<
" to match type " << type <<
"\n");
1154 int64_t dataEltSize,
1155 bool isInt,
bool isSigned) {
1156 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1161 int64_t dataEltSize,
1164 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1169 bool isSigned)
const {
1173 bool isSigned)
const {
1176 dataEltSize / 2, isInt, isSigned);
1187 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1204 const auto &elementSemantics = eltTy.getFloatSemantics();
1215 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1218 const auto &semantics = eltTy.getFloatSemantics();
1220 getType(), {semantics, {*
this, 0}},
1237 ShapedType curType =
getType();
1238 if (curType == newType)
1241 assert(newType.getElementType() == curType.getElementType() &&
1242 "expected the same element type");
1243 assert(newType.getNumElements() == curType.getNumElements() &&
1244 "expected the same number of elements");
1245 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1249 assert(
isSplat() &&
"expected a splat type");
1251 ShapedType curType =
getType();
1252 if (curType == newType)
1255 assert(newType.getElementType() == curType.getElementType() &&
1256 "expected the same element type");
1257 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1265 ShapedType curType =
getType();
1266 Type curElType = curType.getElementType();
1267 if (curElType == newElType)
1272 "expected element types with the same bitwidth");
1273 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1280 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1286 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1295 return getType().getElementType();
1299 return getType().getNumElements();
1307 template <
typename APRangeT>
1309 APRangeT &&values) {
1310 size_t numValues = llvm::size(values);
1313 for (
auto it = values.begin(), e = values.end(); it != e;
1314 ++it, offset += storageWidth) {
1315 assert((*it).getBitWidth() <= storageWidth);
1320 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1321 data[0] = data[0] ? -1 : 0;
1328 size_t storageWidth,
1330 std::vector<char> data;
1331 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1333 return DenseIntOrFPElementsAttr::getRaw(type, data);
1340 size_t storageWidth,
1342 std::vector<char> data;
1344 return DenseIntOrFPElementsAttr::getRaw(type, data);
1349 assert(type.hasStaticShape() &&
"type must have static shape");
1362 int64_t dataEltSize,
1366 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1367 dataEltSize / 2, isInt, isSigned) &&
1368 "Try re-running with -debug-only=builtinattributes");
1370 int64_t numElements = data.size() / dataEltSize;
1372 assert(numElements == 1 || numElements == type.getNumElements());
1373 return getRaw(type, data);
1380 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1381 int64_t dataEltSize,
bool isInt,
1385 "Try re-running with -debug-only=builtinattributes");
1387 int64_t numElements = data.size() / dataEltSize;
1388 assert(numElements == 1 || numElements == type.getNumElements());
1390 return getRaw(type, data);
1393 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1394 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1395 size_t numElements) {
1396 using llvm::support::ulittle16_t;
1397 using llvm::support::ulittle32_t;
1398 using llvm::support::ulittle64_t;
1400 assert(llvm::endianness::native == llvm::endianness::big);
1404 switch (elementBitWidth) {
1406 const ulittle16_t *inRawDataPos =
1407 reinterpret_cast<const ulittle16_t *
>(inRawData);
1408 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1409 std::copy_n(inRawDataPos, numElements, outDataPos);
1413 const ulittle32_t *inRawDataPos =
1414 reinterpret_cast<const ulittle32_t *
>(inRawData);
1415 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1416 std::copy_n(inRawDataPos, numElements, outDataPos);
1420 const ulittle64_t *inRawDataPos =
1421 reinterpret_cast<const ulittle64_t *
>(inRawData);
1422 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1423 std::copy_n(inRawDataPos, numElements, outDataPos);
1427 size_t nBytes = elementBitWidth / CHAR_BIT;
1428 for (
size_t i = 0; i < nBytes; i++)
1429 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1435 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1438 size_t numElements = type.getNumElements();
1439 Type elementType = type.getElementType();
1440 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1441 elementType = complexTy.getElementType();
1442 numElements = numElements * 2;
1445 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1446 inRawData.size() <= outRawData.size());
1447 if (elementBitWidth <= CHAR_BIT)
1448 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1450 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1451 elementBitWidth, numElements);
1458 template <
typename Fn,
typename Attr>
1460 Type newElementType,
1465 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1467 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1471 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1472 auto newInt = mapping(value);
1473 assert(newInt.getBitWidth() == bitWidth);
1474 writeBits(data.data(), index * storageBitWidth, newInt);
1478 if (attr.isSplat()) {
1479 if (bitWidth == 1) {
1481 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1483 processElt(*attr.begin(), 0);
1485 return newArrayType;
1489 uint64_t elementIdx = 0;
1490 for (
auto value : attr)
1491 processElt(value, elementIdx++);
1492 return newArrayType;
1501 return getRaw(newArrayType, elementData);
1506 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1507 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1520 return getRaw(newArrayType, elementData);
1525 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1526 return denseAttr.getType().getElementType().isIntOrIndex();
1537 return Base::get(type.getContext(), type, handle);
1547 return get(type, manager.insert(blobName, std::move(blob)));
1556 template <
typename T>
1557 struct DenseResourceAttrUtil;
1558 template <
size_t w
idth,
bool isSigned>
1559 struct DenseResourceElementsAttrIntUtil {
1560 static bool checkElementType(
Type eltType) {
1561 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1562 if (!type || type.getWidth() != width)
1564 return isSigned ? !type.isUnsigned() : !type.isSigned();
1568 struct DenseResourceAttrUtil<bool> {
1569 static bool checkElementType(
Type eltType) {
1574 struct DenseResourceAttrUtil<int8_t>
1575 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1577 struct DenseResourceAttrUtil<uint8_t>
1578 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1580 struct DenseResourceAttrUtil<int16_t>
1581 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1583 struct DenseResourceAttrUtil<uint16_t>
1584 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1586 struct DenseResourceAttrUtil<int32_t>
1587 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1589 struct DenseResourceAttrUtil<uint32_t>
1590 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1592 struct DenseResourceAttrUtil<int64_t>
1593 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1595 struct DenseResourceAttrUtil<uint64_t>
1596 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1598 struct DenseResourceAttrUtil<float> {
1599 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1602 struct DenseResourceAttrUtil<double> {
1603 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1607 template <
typename T>
1613 "alignment mismatch between expected alignment and blob alignment");
1614 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1615 "size mismatch between expected element width and blob size");
1616 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1617 "invalid shape element type for provided type `T`");
1618 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1622 template <
typename T>
1623 std::optional<ArrayRef<T>>
1626 return blob->template getDataAs<T>();
1627 return std::nullopt;
1630 template <
typename T>
1632 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1633 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1634 resourceAttr.getElementType());
1659 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1661 return APFloat(eltType.getFloatSemantics());
1665 APInt SparseElementsAttr::getZeroAPInt()
const {
1671 Attribute SparseElementsAttr::getZeroAttr()
const {
1675 if (llvm::isa<FloatType>(eltType))
1679 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1680 auto eltType = complexTy.getElementType();
1682 if (llvm::isa<FloatType>(eltType))
1691 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1700 std::vector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1701 std::vector<ptrdiff_t> flatSparseIndices;
1706 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1707 if (sparseIndices.isSplat()) {
1709 *sparseIndexValues.begin());
1710 flatSparseIndices.push_back(getFlattenedIndex(indices));
1711 return flatSparseIndices;
1715 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1716 size_t rank =
getType().getRank();
1717 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1718 flatSparseIndices.push_back(getFlattenedIndex(
1719 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1720 return flatSparseIndices;
1727 ShapedType valuesType = values.
getType();
1728 if (valuesType.getRank() != 1)
1729 return emitError() <<
"expected 1-d tensor for sparse element values";
1732 ShapedType indicesType = sparseIndices.getType();
1733 auto emitShapeError = [&]() {
1734 return emitError() <<
"expected shape ([" << type.getShape()
1735 <<
"]); inferred shape of indices literal (["
1736 << indicesType.getShape()
1737 <<
"]); inferred shape of values literal (["
1738 << valuesType.getShape() <<
"])";
1741 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1742 if (indicesRank == 2) {
1743 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1744 return emitShapeError();
1745 }
else if (indicesRank != 1 || rank != 1) {
1746 return emitShapeError();
1749 int64_t numSparseIndices = indicesType.getDimSize(0);
1750 if (numSparseIndices != valuesType.getDimSize(0))
1751 return emitShapeError();
1756 <<
"sparse index #" << indexNum
1757 <<
" is not contained within the value shape, with index=[" << index
1758 <<
"], and type=" << type;
1762 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1763 if (sparseIndices.isSplat()) {
1765 if (!ElementsAttr::isValidIndex(type, indices))
1766 return emitIndexError(0, indices);
1771 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1774 if (!ElementsAttr::isValidIndex(type, index))
1775 return emitIndexError(i, index);
1790 return getImpl()->referencedAttr;
1801 unsigned nSymbols = 0;
1805 if (!ShapedType::isDynamic(offset)) {
1816 auto dim = en.index();
1817 auto stride = en.value();
1818 assert(stride != 0 &&
"Invalid stride specification");
1822 if (!ShapedType::isDynamic(stride))
1827 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.