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";
264 int64_t &offset)
const {
265 llvm::append_range(strides, getStrides());
266 offset = getOffset();
274 StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
281 if (twine.isTriviallyEmpty())
293 StringRef StringAttr::getValue()
const {
return getImpl()->value; }
297 Dialect *StringAttr::getReferencedDialect()
const {
298 return getImpl()->referencedDialect;
305 double FloatAttr::getValueAsDouble()
const {
306 return getValueAsDouble(getValue());
308 double FloatAttr::getValueAsDouble(APFloat value) {
309 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
310 bool losesInfo =
false;
311 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
314 return value.convertToDouble();
318 Type type, APFloat value) {
320 if (!llvm::isa<FloatType>(type))
321 return emitError() <<
"expected floating point type";
324 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
325 &value.getSemantics()) {
327 <<
"FloatAttr type doesn't match the type implied by its value";
342 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
346 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
352 assert(symName &&
"value does not have a valid symbol name");
356 StringAttr SymbolRefAttr::getLeafReference()
const {
358 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
365 int64_t IntegerAttr::getInt()
const {
367 "must be signless integer");
368 return getValue().getSExtValue();
371 int64_t IntegerAttr::getSInt()
const {
372 assert(
getType().isSignedInteger() &&
"must be signed integer");
373 return getValue().getSExtValue();
376 uint64_t IntegerAttr::getUInt()
const {
377 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
378 return getValue().getZExtValue();
383 APSInt IntegerAttr::getAPSInt()
const {
384 assert(!
getType().isSignlessInteger() &&
385 "Signless integers don't carry a sign for APSInt");
386 return APSInt(getValue(),
getType().isUnsignedInteger());
390 Type type, APInt value) {
391 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
392 if (integerType.getWidth() != value.getBitWidth())
393 return emitError() <<
"integer type bit width (" << integerType.getWidth()
394 <<
") doesn't match value bit width ("
395 << value.getBitWidth() <<
")";
398 if (llvm::isa<IndexType>(type)) {
399 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
401 <<
"value bit width (" << value.getBitWidth()
402 <<
") doesn't match index type internal storage bit width ("
403 << IndexType::kInternalStorageBitWidth <<
")";
406 return emitError() <<
"expected integer or index type";
409 BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
410 auto attr =
Base::get(type.getContext(), type, APInt(1, value));
411 return llvm::cast<BoolAttr>(attr);
419 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
420 return storage->value.getBoolValue();
424 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
425 return intAttr && intAttr.getType().isSignlessInteger(1);
433 StringAttr dialect, StringRef attrData,
436 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
443 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
444 <<
" attribute created with unregistered dialect. If this is "
445 "intended, please call allowUnregisteredDialects() on the "
446 "MLIRContext, or use -allow-unregistered-dialect with "
447 "the MLIR opt tool used";
463 return origWidth == 1 ? origWidth : llvm::alignTo<8>(origWidth);
470 static void setBit(
char *rawData,
size_t bitPos,
bool value) {
472 rawData[bitPos / CHAR_BIT] |= (1 << (bitPos % CHAR_BIT));
474 rawData[bitPos / CHAR_BIT] &= ~(1 << (bitPos % CHAR_BIT));
478 static bool getBit(
const char *rawData,
size_t bitPos) {
479 return (rawData[bitPos / CHAR_BIT] & (1 << (bitPos % CHAR_BIT))) != 0;
486 assert(llvm::endianness::native == llvm::endianness::big);
487 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
492 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
493 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
494 numFilledWords, result);
498 size_t lastWordPos = numFilledWords;
500 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
501 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
502 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
506 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
507 valueLE.begin(), result + lastWordPos,
508 (numBytes - lastWordPos) * CHAR_BIT, 1);
515 assert(llvm::endianness::native == llvm::endianness::big);
516 assert(result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
523 size_t numFilledWords = (result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
525 inArray, numFilledWords,
526 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())));
531 size_t lastWordPos = numFilledWords;
533 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
534 inArray + lastWordPos, inArrayLE.begin(),
535 (numBytes - lastWordPos) * CHAR_BIT, 1);
539 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
541 const_cast<char *
>(
reinterpret_cast<const char *
>(result.getRawData())) +
543 APInt::APINT_BITS_PER_WORD, 1);
547 static void writeBits(
char *rawData,
size_t bitPos, APInt value) {
548 size_t bitWidth = value.getBitWidth();
552 return setBit(rawData, bitPos, value.isOne());
555 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
556 if (llvm::endianness::native == llvm::endianness::big) {
563 rawData + (bitPos / CHAR_BIT));
565 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
567 rawData + (bitPos / CHAR_BIT));
573 static APInt
readBits(
const char *rawData,
size_t bitPos,
size_t bitWidth) {
576 return APInt(1,
getBit(rawData, bitPos) ? 1 : 0);
579 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
580 APInt result(bitWidth, 0);
581 if (llvm::endianness::native == llvm::endianness::big) {
590 std::copy_n(rawData + (bitPos / CHAR_BIT),
593 reinterpret_cast<const char *
>(result.getRawData())));
600 template <
typename Values>
602 return (values.size() == 1) ||
603 (type.getNumElements() ==
static_cast<int64_t
>(values.size()));
614 DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
616 :
llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
618 attr.getAsOpaquePointer(), index) {}
622 Type eltTy = owner.getElementType();
623 if (llvm::dyn_cast<IntegerType>(eltTy))
625 if (llvm::isa<IndexType>(eltTy))
627 if (
auto floatEltTy = llvm::dyn_cast<FloatType>(eltTy)) {
632 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltTy)) {
633 auto complexEltTy = complexTy.getElementType();
635 if (llvm::isa<IntegerType>(complexEltTy)) {
636 auto value = *complexIntIt;
644 llvm::cast<FloatType>(complexEltTy).getFloatSemantics(), complexIntIt);
645 auto value = *complexFloatIt;
651 if (llvm::isa<DenseStringElementsAttr>(owner)) {
653 return StringAttr::get(owner.isSplat() ? vals.front() : vals[index], eltTy);
655 llvm_unreachable(
"unexpected element type");
662 DenseElementsAttr::BoolElementIterator::BoolElementIterator(
668 return getBit(getData(), getDataIndex());
675 DenseElementsAttr::IntElementIterator::IntElementIterator(
691 DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
694 std::complex<APInt>, std::complex<APInt>,
695 std::complex<APInt>>(
697 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
704 size_t offset = getDataIndex() * storageWidth * 2;
705 return {
readBits(getData(), offset, bitWidth),
706 readBits(getData(), offset + storageWidth, bitWidth)};
717 return emitError() <<
"expected integer or floating point element type";
718 int64_t dataSize = rawData.size();
719 int64_t elementSize =
721 if (
size * elementSize != dataSize) {
722 return emitError() <<
"expected data size (" <<
size <<
" elements, "
724 <<
" bytes each) does not match: " << dataSize
733 template <
size_t width,
734 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
735 struct DenseArrayAttrIntUtil {
736 static bool checkElementType(
Type eltType) {
737 auto type = llvm::dyn_cast<IntegerType>(eltType);
738 if (!type || type.getWidth() != width)
740 return type.getSignedness() == signedness;
747 template <
typename T>
748 static void printElement(raw_ostream &os, T value) {
752 template <
typename T>
753 static ParseResult parseElement(
AsmParser &parser, T &value) {
757 template <
typename T>
758 struct DenseArrayAttrUtil;
763 struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
764 static void printElement(raw_ostream &os,
bool value) {
765 os << (value ?
"true" :
"false");
772 struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
773 static void printElement(raw_ostream &os, int8_t value) {
774 os << static_cast<int>(value);
778 struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
780 struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
782 struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
786 struct DenseArrayAttrUtil<float> {
787 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
789 static void printElement(raw_ostream &os,
float value) { os << value; }
792 static ParseResult parseElement(
AsmParser &parser,
float &value) {
803 struct DenseArrayAttrUtil<double> {
804 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
806 static void printElement(raw_ostream &os,
float value) { os << value; }
807 static ParseResult parseElement(
AsmParser &parser,
double &value) {
813 template <
typename T>
818 template <
typename T>
820 llvm::interleaveComma(asArrayRef(), os, [&](T value) {
821 DenseArrayAttrUtil<T>::printElement(os, value);
825 template <
typename T>
828 printWithoutBraces(os);
833 template <
typename T>
839 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
841 data.push_back(value);
849 template <
typename T>
856 Attribute result = parseWithoutBraces(parser, odsType);
863 template <
typename T>
866 assert((raw.size() %
sizeof(T)) == 0);
867 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
868 raw.size() /
sizeof(T));
872 template <
typename T>
876 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
877 content.size() *
sizeof(T));
878 return llvm::cast<DenseArrayAttrImpl<T>>(
879 Base::get(context, elementType, content.size(), rawArray));
882 template <
typename T>
884 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
885 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
908 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
915 Type eltType = type.getElementType();
918 if (
auto complexType = llvm::dyn_cast<ComplexType>(eltType)) {
919 if (complexType.getElementType().isIntOrIndex()) {
921 complexValues.reserve(values.size());
923 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
924 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
925 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
926 auto attr0 = arrayAttr[0];
927 auto attr1 = arrayAttr[1];
928 complexValues.push_back(
929 std::complex<APInt>(llvm::cast<IntegerAttr>(attr0).getValue(),
930 llvm::cast<IntegerAttr>(attr1).getValue()));
936 complexValues.reserve(values.size());
938 assert(llvm::isa<ArrayAttr>(attr) &&
"expected ArrayAttr for complex");
939 auto arrayAttr = llvm::cast<ArrayAttr>(attr);
940 assert(arrayAttr.size() == 2 &&
"expected 2 element for complex");
941 auto attr0 = arrayAttr[0];
942 auto attr1 = arrayAttr[1];
943 complexValues.push_back(
944 std::complex<APFloat>(llvm::cast<FloatAttr>(attr0).getValue(),
945 llvm::cast<FloatAttr>(attr1).getValue()));
954 stringValues.reserve(values.size());
956 assert(llvm::isa<StringAttr>(attr) &&
957 "expected string value for non integer/index/float element");
958 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
960 return get(type, stringValues);
971 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
972 if (
auto floatAttr = llvm::dyn_cast<FloatAttr>(values[i])) {
973 assert(floatAttr.getType() == eltType &&
974 "expected float attribute type to equal element type");
975 intVal = floatAttr.getValue().bitcastToAPInt();
977 auto intAttr = llvm::cast<IntegerAttr>(values[i]);
978 assert(intAttr.getType() == eltType &&
979 "expected integer attribute type to equal element type");
980 intVal = intAttr.getValue();
983 assert(intVal.getBitWidth() == bitWidth &&
984 "expected value to have same bitwidth as element type");
985 writeBits(data.data(), i * storageBitWidth, intVal);
989 if (values.size() == 1 && eltType.
isInteger(1))
990 data[0] = data[0] ? -1 : 0;
992 return DenseIntOrFPElementsAttr::getRaw(type, data);
998 assert(type.getElementType().isInteger(1));
1002 if (!values.empty()) {
1004 bool firstValue = values[0];
1005 for (
int i = 0, e = values.size(); i != e; ++i) {
1006 isSplat &= values[i] == firstValue;
1007 setBit(buff.data(), i, values[i]);
1013 buff[0] = values[0] ? -1 : 0;
1017 return DenseIntOrFPElementsAttr::getRaw(type, buff);
1022 assert(!type.getElementType().isIntOrFloat());
1031 assert(type.getElementType().isIntOrIndex());
1034 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1037 ArrayRef<std::complex<APInt>> values) {
1038 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1039 assert(llvm::isa<IntegerType>(complex.getElementType()));
1042 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
1044 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
1052 assert(llvm::isa<FloatType>(type.getElementType()));
1055 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
1059 ArrayRef<std::complex<APFloat>> values) {
1060 ComplexType complex = llvm::cast<ComplexType>(type.getElementType());
1061 assert(llvm::isa<FloatType>(complex.getElementType()));
1066 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
1074 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
1080 bool &detectedSplat) {
1082 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
1083 int64_t numElements = type.getNumElements();
1086 detectedSplat = numElements == 1;
1089 if (storageWidth == 1) {
1092 if (rawBuffer.size() == 1) {
1093 auto rawByte =
static_cast<uint8_t
>(rawBuffer[0]);
1094 if (rawByte == 0 || rawByte == 0xff) {
1095 detectedSplat =
true;
1101 return rawBufferWidth == llvm::alignTo<8>(numElements);
1106 if (rawBufferWidth == storageWidth) {
1107 detectedSplat =
true;
1112 return rawBufferWidth == storageWidth * numElements;
1122 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
1123 if (denseEltBitWidth != dataSize) {
1124 LLVM_DEBUG(llvm::dbgs() <<
"expected dense element bit width "
1125 << denseEltBitWidth <<
" to match data size "
1126 << dataSize <<
" for type " << type <<
"\n");
1132 bool valid = llvm::isa<FloatType>(type);
1134 LLVM_DEBUG(llvm::dbgs()
1135 <<
"expected float type when isInt is false, but found "
1142 auto intType = llvm::dyn_cast<IntegerType>(type);
1144 LLVM_DEBUG(llvm::dbgs()
1145 <<
"expected integer type when isInt is true, but found " << type
1151 if (intType.isSignless())
1154 bool valid = intType.isSigned() == isSigned;
1156 LLVM_DEBUG(llvm::dbgs() <<
"expected signedness " << isSigned
1157 <<
" to match type " << type <<
"\n");
1164 int64_t dataEltSize,
1165 bool isInt,
bool isSigned) {
1166 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1171 int64_t dataEltSize,
1174 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1179 bool isSigned)
const {
1183 bool isSigned)
const {
1186 dataEltSize / 2, isInt, isSigned);
1197 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1214 const auto &elementSemantics = eltTy.getFloatSemantics();
1225 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1228 const auto &semantics = eltTy.getFloatSemantics();
1230 getType(), {semantics, {*
this, 0}},
1247 ShapedType curType =
getType();
1248 if (curType == newType)
1251 assert(newType.getElementType() == curType.getElementType() &&
1252 "expected the same element type");
1253 assert(newType.getNumElements() == curType.getNumElements() &&
1254 "expected the same number of elements");
1255 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1259 assert(
isSplat() &&
"expected a splat type");
1261 ShapedType curType =
getType();
1262 if (curType == newType)
1265 assert(newType.getElementType() == curType.getElementType() &&
1266 "expected the same element type");
1267 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1275 ShapedType curType =
getType();
1276 Type curElType = curType.getElementType();
1277 if (curElType == newElType)
1282 "expected element types with the same bitwidth");
1283 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1290 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1296 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1305 return getType().getElementType();
1309 return getType().getNumElements();
1317 template <
typename APRangeT>
1320 APRangeT &&values) {
1321 size_t numValues = llvm::size(values);
1324 for (
auto it = values.begin(), e = values.end(); it != e;
1325 ++it, offset += storageWidth) {
1326 assert((*it).getBitWidth() <= storageWidth);
1331 if (numValues == 1 && (*values.begin()).getBitWidth() == 1)
1332 data[0] = data[0] ? -1 : 0;
1339 size_t storageWidth,
1342 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1344 return DenseIntOrFPElementsAttr::getRaw(type, data);
1351 size_t storageWidth,
1355 return DenseIntOrFPElementsAttr::getRaw(type, data);
1360 assert(type.hasStaticShape() &&
"type must have static shape");
1373 int64_t dataEltSize,
1377 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1378 dataEltSize / 2, isInt, isSigned) &&
1379 "Try re-running with -debug-only=builtinattributes");
1381 int64_t numElements = data.size() / dataEltSize;
1383 assert(numElements == 1 || numElements == type.getNumElements());
1384 return getRaw(type, data);
1391 DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type,
ArrayRef<char> data,
1392 int64_t dataEltSize,
bool isInt,
1396 "Try re-running with -debug-only=builtinattributes");
1398 int64_t numElements = data.size() / dataEltSize;
1399 assert(numElements == 1 || numElements == type.getNumElements());
1401 return getRaw(type, data);
1404 void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1405 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1406 size_t numElements) {
1407 using llvm::support::ulittle16_t;
1408 using llvm::support::ulittle32_t;
1409 using llvm::support::ulittle64_t;
1411 assert(llvm::endianness::native == llvm::endianness::big);
1415 switch (elementBitWidth) {
1417 const ulittle16_t *inRawDataPos =
1418 reinterpret_cast<const ulittle16_t *
>(inRawData);
1419 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1420 std::copy_n(inRawDataPos, numElements, outDataPos);
1424 const ulittle32_t *inRawDataPos =
1425 reinterpret_cast<const ulittle32_t *
>(inRawData);
1426 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1427 std::copy_n(inRawDataPos, numElements, outDataPos);
1431 const ulittle64_t *inRawDataPos =
1432 reinterpret_cast<const ulittle64_t *
>(inRawData);
1433 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1434 std::copy_n(inRawDataPos, numElements, outDataPos);
1438 size_t nBytes = elementBitWidth / CHAR_BIT;
1439 for (
size_t i = 0; i < nBytes; i++)
1440 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1446 void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1449 size_t numElements = type.getNumElements();
1450 Type elementType = type.getElementType();
1451 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1452 elementType = complexTy.getElementType();
1453 numElements = numElements * 2;
1456 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1457 inRawData.size() <= outRawData.size());
1458 if (elementBitWidth <= CHAR_BIT)
1459 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1461 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1462 elementBitWidth, numElements);
1469 template <
typename Fn,
typename Attr>
1471 Type newElementType,
1476 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1478 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1482 auto processElt = [&](decltype(*attr.begin()) value,
size_t index) {
1483 auto newInt = mapping(value);
1484 assert(newInt.getBitWidth() == bitWidth);
1485 writeBits(data.data(), index * storageBitWidth, newInt);
1489 if (attr.isSplat()) {
1490 if (bitWidth == 1) {
1492 data[0] = mapping(*attr.begin()).isZero() ? 0 : -1;
1494 processElt(*attr.begin(), 0);
1496 return newArrayType;
1500 uint64_t elementIdx = 0;
1501 for (
auto value : attr)
1502 processElt(value, elementIdx++);
1503 return newArrayType;
1512 return getRaw(newArrayType, elementData);
1517 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1518 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1531 return getRaw(newArrayType, elementData);
1536 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1537 return denseAttr.getType().getElementType().isIntOrIndex();
1548 return Base::get(type.getContext(), type, handle);
1558 return get(type, manager.insert(blobName, std::move(blob)));
1563 return blob->getDataAs<
char>();
1574 template <
typename T>
1575 struct DenseResourceAttrUtil;
1576 template <
size_t w
idth,
bool isSigned>
1577 struct DenseResourceElementsAttrIntUtil {
1578 static bool checkElementType(
Type eltType) {
1579 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1580 if (!type || type.getWidth() != width)
1582 return isSigned ? !type.isUnsigned() : !type.isSigned();
1586 struct DenseResourceAttrUtil<bool> {
1587 static bool checkElementType(
Type eltType) {
1592 struct DenseResourceAttrUtil<int8_t>
1593 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1595 struct DenseResourceAttrUtil<uint8_t>
1596 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1598 struct DenseResourceAttrUtil<int16_t>
1599 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1601 struct DenseResourceAttrUtil<uint16_t>
1602 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1604 struct DenseResourceAttrUtil<int32_t>
1605 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1607 struct DenseResourceAttrUtil<uint32_t>
1608 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1610 struct DenseResourceAttrUtil<int64_t>
1611 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1613 struct DenseResourceAttrUtil<uint64_t>
1614 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1616 struct DenseResourceAttrUtil<float> {
1617 static bool checkElementType(
Type eltType) {
return eltType.
isF32(); }
1620 struct DenseResourceAttrUtil<double> {
1621 static bool checkElementType(
Type eltType) {
return eltType.
isF64(); }
1625 template <
typename T>
1631 "alignment mismatch between expected alignment and blob alignment");
1632 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1633 "size mismatch between expected element width and blob size");
1634 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1635 "invalid shape element type for provided type `T`");
1636 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1640 template <
typename T>
1641 std::optional<ArrayRef<T>>
1644 return blob->template getDataAs<T>();
1645 return std::nullopt;
1648 template <
typename T>
1650 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1651 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1652 resourceAttr.getElementType());
1677 APFloat SparseElementsAttr::getZeroAPFloat()
const {
1679 return APFloat(eltType.getFloatSemantics());
1683 APInt SparseElementsAttr::getZeroAPInt()
const {
1689 Attribute SparseElementsAttr::getZeroAttr()
const {
1693 if (llvm::isa<FloatType>(eltType))
1697 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1698 auto eltType = complexTy.getElementType();
1700 if (llvm::isa<FloatType>(eltType))
1709 if (llvm::isa<DenseStringElementsAttr>(
getValues()))
1724 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1725 if (sparseIndices.isSplat()) {
1727 *sparseIndexValues.begin());
1728 flatSparseIndices.push_back(getFlattenedIndex(indices));
1729 return flatSparseIndices;
1733 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1734 size_t rank =
getType().getRank();
1735 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1736 flatSparseIndices.push_back(getFlattenedIndex(
1737 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1738 return flatSparseIndices;
1745 ShapedType valuesType = values.
getType();
1746 if (valuesType.getRank() != 1)
1747 return emitError() <<
"expected 1-d tensor for sparse element values";
1750 ShapedType indicesType = sparseIndices.getType();
1751 auto emitShapeError = [&]() {
1752 return emitError() <<
"expected shape ([" << type.getShape()
1753 <<
"]); inferred shape of indices literal (["
1754 << indicesType.getShape()
1755 <<
"]); inferred shape of values literal (["
1756 << valuesType.getShape() <<
"])";
1759 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1760 if (indicesRank == 2) {
1761 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1762 return emitShapeError();
1763 }
else if (indicesRank != 1 || rank != 1) {
1764 return emitShapeError();
1767 int64_t numSparseIndices = indicesType.getDimSize(0);
1768 if (numSparseIndices != valuesType.getDimSize(0))
1769 return emitShapeError();
1774 <<
"sparse index #" << indexNum
1775 <<
" is not contained within the value shape, with index=[" << index
1776 <<
"], and type=" << type;
1780 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1781 if (sparseIndices.isSplat()) {
1783 if (!ElementsAttr::isValidIndex(type, indices))
1784 return emitIndexError(0, indices);
1789 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1792 if (!ElementsAttr::isValidIndex(type, index))
1793 return emitIndexError(i, index);
1808 return getImpl()->referencedAttr;
1819 unsigned nSymbols = 0;
1823 if (!ShapedType::isDynamic(offset)) {
1834 auto dim = en.index();
1835 auto stride = en.value();
1839 if (!ShapedType::isDynamic(stride))
1844 expr = expr + d * mult;
static LogicalResult getStridesAndOffset(AffineMap m, ArrayRef< int64_t > shape, SmallVectorImpl< AffineExpr > &strides, AffineExpr &offset)
A stride specification is a list of integer values that are either static or dynamic (encoded with Sh...
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
static bool isValidIntOrFloat(Type type, int64_t dataEltSize, bool isInt, bool isSigned)
Check the information for a C++ data type, check if this type is valid for the current attribute.
static void copyAPIntToArrayForBEmachine(APInt value, size_t numBytes, char *result)
Copy actual numBytes data from value (APInt) to char array(result) for BE format.
static ShapedType mappingHelper(Fn mapping, Attr &attr, ShapedType inType, Type newElementType, llvm::SmallVectorImpl< char > &data)
static void setBit(char *rawData, size_t bitPos, bool value)
Set a bit to a specific value.
static bool hasSameNumElementsOrSplat(ShapedType type, const Values &values)
Returns true if 'values' corresponds to a splat, i.e.
static void writeAPIntsToBuffer(size_t storageWidth, SmallVectorImpl< char > &data, APRangeT &&values)
Utility method to write a range of APInt values to a buffer.
static void writeBits(char *rawData, size_t bitPos, APInt value)
Writes value to the bit position bitPos in array rawData.
static bool dictionaryAttrSort(ArrayRef< NamedAttribute > value, SmallVectorImpl< NamedAttribute > &storage)
Helper function that does either an in place sort or sorts from source array into destination.
static size_t getDenseElementStorageWidth(size_t origWidth)
Get the bitwidth of a dense element type within the buffer.
static void copyArrayToAPIntForBEmachine(const char *inArray, size_t numBytes, APInt &result)
Copy numBytes data from inArray(char array) to result(APINT) for BE format.
static bool getBit(const char *rawData, size_t bitPos)
Return the value of the specified bit.
static bool isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
static APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth)
Reads the next bitWidth bits from the bit position bitPos in array rawData.
static MLIRContext * getContext(OpFoldResult val)
static bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
static DimensionSize operator*(DimensionSize lhs, DimensionSize rhs)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalRSquare()=0
Parse a ] token if present.
virtual ParseResult parseFloat(double &result)=0
Parse a floating point value from the stream.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
This class represents a processed binary blob of data.
size_t getDataAlignment() const
Return the alignment of the underlying data.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Attributes are known-constant values of operations.
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
MLIRContext * getContext() const
Return the context this attribute belongs to.
ImplType * getImpl() const
Return the internal Attribute implementation.
static Attribute getFromOpaquePointer(const void *ptr)
Construct an attribute from the opaque pointer representation.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
static bool classof(Attribute attr)
Methods for support type inquiry through isa, cast, and dyn_cast.
bool getValue() const
Return the boolean value of this attribute.
A utility iterator that allows walking over the internal bool values.
bool operator*() const
Accesses the bool value at this iterator position.
Iterator for walking over complex APFloat values.
A utility iterator that allows walking over the internal raw complex APInt values.
std::complex< APInt > operator*() const
Accesses the raw std::complex<APInt> value at this iterator position.
Iterator for walking over APFloat values.
A utility iterator that allows walking over the internal raw APInt values.
APInt operator*() const
Accesses the raw APInt value at this iterator position.
An attribute that represents a reference to a dense vector or tensor object.
ArrayRef< StringRef > getRawStringData() const
Return the raw StringRef data held by this attribute.
IntElementIterator raw_int_begin() const
Iterators to various elements that require out-of-line definition.
static DenseElementsAttr getRawIntOrFloat(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of integer or floating-point typ...
static DenseElementsAttr getRawComplex(ShapedType type, ArrayRef< char > data, int64_t dataEltSize, bool isInt, bool isSigned)
Overload of the raw 'get' method that asserts that the given type is of complex type.
static bool classof(Attribute attr)
Method for support type inquiry through isa, cast and dyn_cast.
bool isValidComplex(int64_t dataEltSize, bool isInt, bool isSigned) const
auto getValues() const
Return the held element values as a range of the given type.
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
int64_t getNumElements() const
Returns the number of elements held by this attribute.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
int64_t size() const
Returns the number of elements held by this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ArrayRef< char > getRawData() const
Return the raw storage data held by this attribute.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each int value to a new underlying APInt.
Type getElementType() const
Return the element type of this DenseElementsAttr.
FailureOr< iterator_range_impl< ComplexFloatElementIterator > > tryGetComplexFloatValues() const
IntElementIterator raw_int_end() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
FailureOr< iterator_range_impl< FloatElementIterator > > tryGetFloatValues() const
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer, bool &detectedSplat)
Returns true if the given buffer is a valid raw buffer for the given type.
DenseElementsAttr bitcast(Type newElType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has bitcast eleme...
bool isValidIntOrFloat(int64_t dataEltSize, bool isInt, bool isSigned) const
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
FailureOr< iterator_range_impl< ComplexIntElementIterator > > tryGetComplexIntValues() const
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APFloat &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
An attribute that represents a reference to a dense integer vector or tensor object.
static bool classof(Attribute attr)
Method for supporting type inquiry through isa, cast and dyn_cast.
DenseElementsAttr mapValues(Type newElementType, function_ref< APInt(const APInt &)> mapping) const
Generates a new DenseElementsAttr by mapping each value attribute, and constructing the DenseElements...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
An attribute that associates a referenced attribute with a unique identifier.
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
Attribute getReferencedAttr() const
Returns the referenced attribute.
A symbol reference with a reference path containing a single element.
This class represents a diagnostic that is inflight and set to be reported.
MLIRContext is the top-level object for a collection of MLIR operations.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
NamedAttribute represents a combination of a name and an Attribute value.
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
bool isInteger() const
Return true if this is an integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
Impl iterator for indexed DenseElementsAttr iterators that records a data pointer and data index that...
Base class for DenseResourceElementsAttr that is instantiated and specialized for each supported elem...
This class provides iterator utilities for an ElementsAttr range.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator)
Divides the known min value of the numerator by the denominator and rounds the result up to the next ...
std::pair< IteratorT, bool > findAttrSorted(IteratorT first, IteratorT last, StringRef name)
Using llvm::lower_bound requires an extra string comparison to check whether the returned iterator po...
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
AffineMap makeStridedLinearLayoutMap(ArrayRef< int64_t > strides, int64_t offset, MLIRContext *context)
Given a list of strides (in which ShapedType::kDynamic represents a dynamic value),...
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
This class defines a dialect specific handle to a resource blob.
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
Get the interface for the dialect that owns handles of this type.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
static const char kSplatTrue
The values used to denote a boolean splat value.
static const char kSplatFalse
An attribute representing a reference to a dense vector or tensor object containing strings.