21#include "llvm/ADT/APSInt.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/DebugLog.h"
24#include "llvm/Support/Endian.h"
27#define DEBUG_TYPE "builtinattributes"
36#define GET_ATTRDEF_CLASSES
37#include "mlir/IR/BuiltinAttributes.cpp.inc"
43void BuiltinDialect::registerAttributes() {
45#define GET_ATTRDEF_LIST
46#include "mlir/IR/BuiltinAttributes.cpp.inc"
48 addAttributes<DistinctAttr>();
59template <
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());
101static 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");
132std::optional<NamedAttribute>
140DictionaryAttr DictionaryAttr::get(
MLIRContext *context,
143 return DictionaryAttr::getEmpty(context);
146 SmallVector<NamedAttribute, 8> storage;
150 "DictionaryAttr element names must be unique");
151 return Base::get(context, value);
155DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
158 return DictionaryAttr::getEmpty(context);
160 assert(llvm::is_sorted(
161 value, [](NamedAttribute l, NamedAttribute r) {
return l < r; }) &&
162 "expected attribute values to be sorted");
164 "DictionaryAttr element names must be unique");
165 return Base::get(context, value);
169Attribute DictionaryAttr::get(StringRef name)
const {
170 auto it = impl::findAttrSorted(begin(), end(), name);
171 return it.second ? it.first->getValue() : Attribute();
173Attribute DictionaryAttr::get(StringAttr name)
const {
174 auto it = impl::findAttrSorted(begin(), end(), name);
175 return it.second ? it.first->getValue() : Attribute();
179std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
180 auto it = impl::findAttrSorted(begin(), end(), name);
181 return it.second ? *it.first : std::optional<NamedAttribute>();
183std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
184 auto it = impl::findAttrSorted(begin(), end(), name);
185 return it.second ? *it.first : std::optional<NamedAttribute>();
189bool DictionaryAttr::contains(StringRef name)
const {
190 return impl::findAttrSorted(begin(), end(), name).second;
192bool DictionaryAttr::contains(StringAttr name)
const {
193 return impl::findAttrSorted(begin(), end(), name).second;
196DictionaryAttr::iterator DictionaryAttr::begin()
const {
197 return getValue().begin();
199DictionaryAttr::iterator DictionaryAttr::end()
const {
200 return getValue().end();
202size_t DictionaryAttr::size()
const {
return getValue().size(); }
204DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
205 return Base::get(context, ArrayRef<NamedAttribute>());
213void StridedLayoutAttr::print(llvm::raw_ostream &os)
const {
214 auto printIntOrQuestion = [&](
int64_t value) {
215 if (ShapedType::isDynamic(value))
222 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
225 if (getOffset() != 0) {
227 printIntOrQuestion(getOffset());
234bool StridedLayoutAttr::hasStaticLayout()
const {
235 return ShapedType::isStatic(getOffset()) &&
236 ShapedType::isStaticShape(getStrides());
240AffineMap StridedLayoutAttr::getAffineMap()
const {
252LogicalResult StridedLayoutAttr::verifyLayout(
255 if (
shape.size() != getStrides().size())
256 return emitError() <<
"expected the number of strides to match the rank";
265 llvm::append_range(strides, getStrides());
266 offset = getOffset();
274StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
275 return Base::get(context,
"", NoneType::get(context));
279StringAttr StringAttr::get(
MLIRContext *context,
const Twine &twine) {
281 if (twine.isTriviallyEmpty())
283 SmallVector<char, 32> tempStr;
284 return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
288StringAttr StringAttr::get(
const Twine &twine,
Type type) {
289 SmallVector<char, 32> tempStr;
290 return Base::get(type.
getContext(), twine.toStringRef(tempStr), type);
293StringRef StringAttr::getValue()
const {
return getImpl()->value; }
295Type StringAttr::getType()
const {
return getImpl()->type; }
297Dialect *StringAttr::getReferencedDialect()
const {
298 return getImpl()->referencedDialect;
305double FloatAttr::getValueAsDouble()
const {
306 return getValueAsDouble(getValue());
308double 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";
336SymbolRefAttr SymbolRefAttr::get(
MLIRContext *ctx, StringRef value,
338 return get(StringAttr::get(ctx, value), nestedRefs);
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");
353 return SymbolRefAttr::get(symName);
356StringAttr SymbolRefAttr::getLeafReference()
const {
357 ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
358 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
365int64_t IntegerAttr::getInt()
const {
367 "must be signless integer");
368 return getValue().getSExtValue();
371int64_t IntegerAttr::getSInt()
const {
372 assert(
getType().isSignedInteger() &&
"must be signed integer");
373 return getValue().getSExtValue();
376uint64_t IntegerAttr::getUInt()
const {
377 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
378 return getValue().getZExtValue();
383APSInt 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";
409BoolAttr 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";
460 return llvm::alignTo<8>(origWidth);
470 assert(llvm::endianness::native == llvm::endianness::big);
471 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
476 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
477 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
482 size_t lastWordPos = numFilledWords;
484 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
485 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
486 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
490 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
491 valueLE.begin(),
result + lastWordPos,
492 (numBytes - lastWordPos) * CHAR_BIT, 1);
499 assert(llvm::endianness::native == llvm::endianness::big);
500 assert(
result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
507 size_t numFilledWords = (
result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
509 inArray, numFilledWords,
510 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())));
515 size_t lastWordPos = numFilledWords;
517 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
518 inArray + lastWordPos, inArrayLE.begin(),
519 (numBytes - lastWordPos) * CHAR_BIT, 1);
523 DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
525 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())) +
527 APInt::APINT_BITS_PER_WORD, 1);
532 size_t bitWidth = value.getBitWidth();
535 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
536 if (llvm::endianness::native == llvm::endianness::big) {
543 rawData + (bitPos / CHAR_BIT));
545 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
546 llvm::divideCeil(bitWidth, CHAR_BIT),
547 rawData + (bitPos / CHAR_BIT));
556 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
557 APInt
result(bitWidth, 0);
558 if (llvm::endianness::native == llvm::endianness::big) {
565 llvm::divideCeil(bitWidth, CHAR_BIT),
result);
567 std::copy_n(rawData + (bitPos / CHAR_BIT),
568 llvm::divideCeil(bitWidth, CHAR_BIT),
570 reinterpret_cast<const char *
>(
result.getRawData())));
577template <
typename Values>
579 return (values.size() == 1) ||
580 (type.getNumElements() ==
static_cast<int64_t>(values.size()));
591DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
593 : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
595 attr.getAsOpaquePointer(),
index) {}
599 Type eltTy = owner.getElementType();
602 if (llvm::isa<DenseStringElementsAttr>(owner)) {
604 return StringAttr::get(owner.isSplat() ? vals.front() : vals[
index], eltTy);
608 auto denseEltTy = llvm::cast<DenseElementType>(eltTy);
611 size_t bitSize = denseEltTy.getDenseElementBitSize();
612 size_t byteSize = llvm::divideCeil(bitSize, CHAR_BIT);
613 size_t offset = owner.isSplat() ? 0 :
index * byteSize;
614 return denseEltTy.convertToAttribute(rawData.slice(offset, byteSize));
621DenseElementsAttr::BoolElementIterator::BoolElementIterator(
634DenseElementsAttr::IntElementIterator::IntElementIterator(
650DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
656 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
676 return emitError() <<
"expected integer or floating point element type";
677 int64_t dataSize = rawData.size();
680 if (
size * elementSize != dataSize) {
681 return emitError() <<
"expected data size (" <<
size <<
" elements, "
683 <<
" bytes each) does not match: " << dataSize
692template <
size_t width,
693 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
694struct DenseArrayAttrIntUtil {
695 static bool checkElementType(
Type eltType) {
696 auto type = llvm::dyn_cast<IntegerType>(eltType);
697 if (!type || type.getWidth() != width)
699 return type.getSignedness() == signedness;
703 return IntegerType::get(ctx, width, signedness);
706 template <
typename T>
707 static void printElement(raw_ostream &os, T value) {
711 template <
typename T>
712 static ParseResult parseElement(AsmParser &parser, T &value) {
717struct DenseArrayAttrUtil;
722struct DenseArrayAttrUtil<
bool> :
public DenseArrayAttrIntUtil<1> {
723 static void printElement(
raw_ostream &os,
bool value) {
724 os << (value ?
"true" :
"false");
731struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
732 static void printElement(
raw_ostream &os, int8_t value) {
733 os << static_cast<int>(value);
737struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
739struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
741struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
745struct DenseArrayAttrUtil<float> {
746 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
747 static Type
getElementType(MLIRContext *ctx) {
return Float32Type::get(ctx); }
748 static void printElement(raw_ostream &os,
float value) { os << value; }
751 static ParseResult parseElement(AsmParser &parser,
float &value) {
762struct DenseArrayAttrUtil<double> {
763 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
764 static Type
getElementType(MLIRContext *ctx) {
return Float64Type::get(ctx); }
765 static void printElement(raw_ostream &os,
float value) { os << value; }
766 static ParseResult parseElement(AsmParser &parser,
double &value) {
779 llvm::interleaveComma(
asArrayRef(), os, [&](T value) {
780 DenseArrayAttrUtil<T>::printElement(os, value);
798 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
800 data.push_back(value);
825 assert((raw.size() %
sizeof(T)) == 0);
826 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
827 raw.size() /
sizeof(T));
834 Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
835 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
836 content.size() *
sizeof(T));
837 return llvm::cast<DenseArrayAttrImpl<T>>(
838 Base::get(context, elementType, content.size(), rawArray));
843 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
844 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
867 return llvm::isa<DenseIntOrFPElementsAttr, DenseStringElementsAttr>(attr);
873 Type eltType = type.getElementType();
876 if (!llvm::isa<DenseElementType>(eltType)) {
878 stringValues.reserve(values.size());
880 assert(llvm::isa<StringAttr>(attr) &&
881 "expected string value for non-DenseElementType element");
882 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
884 return get(type, stringValues);
888 auto denseEltType = llvm::dyn_cast<DenseElementType>(eltType);
889 assert(denseEltType &&
890 "attempted to get DenseElementsAttr with unsupported element type");
893 LogicalResult
result = denseEltType.convertFromAttribute(attr, data);
897 return DenseIntOrFPElementsAttr::getRaw(type, data);
903 assert(type.getElementType().isInteger(1));
904 return DenseIntOrFPElementsAttr::getRaw(
905 type,
ArrayRef<char>(
reinterpret_cast<const char *
>(values.data()),
911 assert(!type.getElementType().isIntOrFloat());
912 return DenseStringElementsAttr::get(type, values);
920 assert(type.getElementType().isIntOrIndex());
923 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
926 ArrayRef<std::complex<APInt>> values) {
927 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
928 assert(llvm::isa<IntegerType>(
complex.getElementType()));
931 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
933 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, intVals);
941 assert(llvm::isa<FloatType>(type.getElementType()));
944 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, values);
948 ArrayRef<std::complex<APFloat>> values) {
949 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
950 assert(llvm::isa<FloatType>(
complex.getElementType()));
955 return DenseIntOrFPElementsAttr::getRaw(type, storageBitWidth, apVals);
963 return DenseIntOrFPElementsAttr::getRaw(type, rawBuffer);
970 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
971 int64_t numElements = type.getNumElements();
975 return rawBufferWidth == storageWidth ||
976 rawBufferWidth == storageWidth * numElements;
986 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
987 if (denseEltBitWidth != dataSize) {
988 LDBG() <<
"expected dense element bit width " << denseEltBitWidth
989 <<
" to match data size " << dataSize <<
" for type " << type;
995 bool valid = llvm::isa<FloatType>(type);
997 LDBG() <<
"expected float type when isInt is false, but found " << type;
1003 auto intType = llvm::dyn_cast<IntegerType>(type);
1005 LDBG() <<
"expected integer type when isInt is true, but found " << type;
1010 if (intType.isSignless())
1013 bool valid = intType.isSigned() == isSigned;
1015 LDBG() <<
"expected signedness " << isSigned <<
" to match type " << type;
1023 bool isInt,
bool isSigned) {
1024 return DenseIntOrFPElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1032 return DenseIntOrFPElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1037 bool isSigned)
const {
1038 return ::isValidIntOrFloat(
getElementType(), dataEltSize, isInt, isSigned);
1041 bool isSigned)
const {
1042 return ::isValidIntOrFloat(
1044 dataEltSize / 2, isInt, isSigned);
1051 if (isa<DenseStringElementsAttr>(*
this))
1054 size_t storageSize = llvm::divideCeil(
1061 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1078 const auto &elementSemantics = eltTy.getFloatSemantics();
1089 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1092 const auto &semantics = eltTy.getFloatSemantics();
1094 getType(), {semantics, {*
this, 0}},
1111 ShapedType curType =
getType();
1112 if (curType == newType)
1115 assert(newType.getElementType() == curType.getElementType() &&
1116 "expected the same element type");
1117 assert(newType.getNumElements() == curType.getNumElements() &&
1118 "expected the same number of elements");
1119 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1123 assert(
isSplat() &&
"expected a splat type");
1125 ShapedType curType =
getType();
1126 if (curType == newType)
1129 assert(newType.getElementType() == curType.getElementType() &&
1130 "expected the same element type");
1131 return DenseIntOrFPElementsAttr::getRaw(newType,
getRawData());
1139 ShapedType curType =
getType();
1140 Type curElType = curType.getElementType();
1141 if (curElType == newElType)
1146 "expected element types with the same bitwidth");
1147 return DenseIntOrFPElementsAttr::getRaw(curType.clone(newElType),
1154 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1160 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1169 return getType().getElementType();
1173 return getType().getNumElements();
1181template <
typename APRangeT>
1184 APRangeT &&values) {
1185 size_t numValues = llvm::size(values);
1186 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1188 for (
auto it = values.begin(), e = values.end(); it != e;
1189 ++it, offset += storageWidth) {
1190 assert((*it).getBitWidth() <= storageWidth);
1198DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1199 size_t storageWidth,
1200 ArrayRef<APFloat> values) {
1201 SmallVector<char> data;
1202 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1204 return DenseIntOrFPElementsAttr::getRaw(type, data);
1210DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1211 size_t storageWidth,
1212 ArrayRef<APInt> values) {
1213 SmallVector<char> data;
1215 return DenseIntOrFPElementsAttr::getRaw(type, data);
1218DenseElementsAttr DenseIntOrFPElementsAttr::getRaw(ShapedType type,
1219 ArrayRef<char> data) {
1220 assert(type.hasStaticShape() &&
"type must have static shape");
1221 assert(isValidRawBuffer(type, data));
1222 return Base::get(type.getContext(), type, data);
1228DenseElementsAttr DenseIntOrFPElementsAttr::getRawComplex(ShapedType type,
1229 ArrayRef<char> data,
1230 int64_t dataEltSize,
1234 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1235 dataEltSize / 2, isInt, isSigned) &&
1236 "Try re-running with -debug-only=builtinattributes");
1238 int64_t numElements = data.size() / dataEltSize;
1240 assert(numElements == 1 || numElements == type.getNumElements());
1241 return getRaw(type, data);
1248DenseIntOrFPElementsAttr::getRawIntOrFloat(ShapedType type, ArrayRef<char> data,
1249 int64_t dataEltSize,
bool isInt,
1253 "Try re-running with -debug-only=builtinattributes");
1255 int64_t numElements = data.size() / dataEltSize;
1256 assert(numElements == 1 || numElements == type.getNumElements());
1258 return getRaw(type, data);
1261void DenseIntOrFPElementsAttr::convertEndianOfCharForBEmachine(
1262 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1263 size_t numElements) {
1264 using llvm::support::ulittle16_t;
1265 using llvm::support::ulittle32_t;
1266 using llvm::support::ulittle64_t;
1268 assert(llvm::endianness::native == llvm::endianness::big);
1272 switch (elementBitWidth) {
1274 const ulittle16_t *inRawDataPos =
1275 reinterpret_cast<const ulittle16_t *
>(inRawData);
1276 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1277 std::copy_n(inRawDataPos, numElements, outDataPos);
1281 const ulittle32_t *inRawDataPos =
1282 reinterpret_cast<const ulittle32_t *
>(inRawData);
1283 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1284 std::copy_n(inRawDataPos, numElements, outDataPos);
1288 const ulittle64_t *inRawDataPos =
1289 reinterpret_cast<const ulittle64_t *
>(inRawData);
1290 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1291 std::copy_n(inRawDataPos, numElements, outDataPos);
1295 size_t nBytes = elementBitWidth / CHAR_BIT;
1296 for (
size_t i = 0; i < nBytes; i++)
1297 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1303void DenseIntOrFPElementsAttr::convertEndianOfArrayRefForBEmachine(
1304 ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1306 size_t numElements = type.getNumElements();
1307 Type elementType = type.getElementType();
1308 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1309 elementType = complexTy.getElementType();
1310 numElements = numElements * 2;
1313 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1314 inRawData.size() <= outRawData.size());
1315 if (elementBitWidth <= CHAR_BIT)
1316 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1318 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1319 elementBitWidth, numElements);
1326template <
typename Fn,
typename Attr>
1328 Type newElementType,
1333 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1335 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1336 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1339 auto processElt = [&](
decltype(*attr.begin()) value,
size_t index) {
1340 auto newInt = mapping(value);
1341 assert(newInt.getBitWidth() == bitWidth);
1346 if (attr.isSplat()) {
1347 processElt(*attr.begin(), 0);
1348 return newArrayType;
1352 uint64_t elementIdx = 0;
1353 for (
auto value : attr)
1354 processElt(value, elementIdx++);
1355 return newArrayType;
1364 return getRaw(newArrayType, elementData);
1369 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1370 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1383 return getRaw(newArrayType, elementData);
1388 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1389 return denseAttr.getType().getElementType().isIntOrIndex();
1397DenseResourceElementsAttr
1398DenseResourceElementsAttr::get(ShapedType type,
1400 return Base::get(type.getContext(), type, handle);
1403DenseResourceElementsAttr DenseResourceElementsAttr::get(ShapedType type,
1410 return get(type, manager.insert(blobName, std::move(blob)));
1413ArrayRef<char> DenseResourceElementsAttr::getData() {
1414 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1415 return blob->getDataAs<
char>();
1426template <
typename T>
1427struct DenseResourceAttrUtil;
1428template <
size_t w
idth,
bool isSigned>
1429struct DenseResourceElementsAttrIntUtil {
1430 static bool checkElementType(Type eltType) {
1431 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1432 if (!type || type.getWidth() != width)
1434 return isSigned ? !type.isUnsigned() : !type.isSigned();
1438struct DenseResourceAttrUtil<bool> {
1439 static bool checkElementType(Type eltType) {
1444struct DenseResourceAttrUtil<int8_t>
1445 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1447struct DenseResourceAttrUtil<uint8_t>
1448 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1450struct DenseResourceAttrUtil<int16_t>
1451 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1453struct DenseResourceAttrUtil<uint16_t>
1454 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1456struct DenseResourceAttrUtil<int32_t>
1457 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1459struct DenseResourceAttrUtil<uint32_t>
1460 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1462struct DenseResourceAttrUtil<int64_t>
1463 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1465struct DenseResourceAttrUtil<uint64_t>
1466 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1468struct DenseResourceAttrUtil<float> {
1469 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
1472struct DenseResourceAttrUtil<double> {
1473 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
1477template <
typename T>
1478DenseResourceElementsAttrBase<T>
1483 "alignment mismatch between expected alignment and blob alignment");
1484 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1485 "size mismatch between expected element width and blob size");
1486 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1487 "invalid shape element type for provided type `T`");
1488 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1489 DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1492template <
typename T>
1493std::optional<ArrayRef<T>>
1496 return blob->template getDataAs<T>();
1497 return std::nullopt;
1500template <
typename T>
1502 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1503 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1504 resourceAttr.getElementType());
1529APFloat SparseElementsAttr::getZeroAPFloat()
const {
1531 return APFloat(eltType.getFloatSemantics());
1535APInt SparseElementsAttr::getZeroAPInt()
const {
1537 return APInt::getZero(eltType.getWidth());
1541Attribute SparseElementsAttr::getZeroAttr()
const {
1545 if (llvm::isa<FloatType>(eltType))
1546 return FloatAttr::get(eltType, 0);
1549 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1550 auto eltType = complexTy.getElementType();
1552 if (llvm::isa<FloatType>(eltType))
1553 zero = FloatAttr::get(eltType, 0);
1555 zero = IntegerAttr::get(eltType, 0);
1556 return ArrayAttr::get(complexTy.getContext(),
1557 ArrayRef<Attribute>{zero, zero});
1561 if (llvm::isa<DenseStringElementsAttr>(getValues()))
1562 return StringAttr::get(
"", eltType);
1565 return IntegerAttr::get(eltType, 0);
1570SmallVector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1571 SmallVector<ptrdiff_t> flatSparseIndices;
1576 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1577 if (sparseIndices.isSplat()) {
1579 *sparseIndexValues.begin());
1580 flatSparseIndices.push_back(getFlattenedIndex(
indices));
1581 return flatSparseIndices;
1585 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1586 size_t rank =
getType().getRank();
1587 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1588 flatSparseIndices.push_back(getFlattenedIndex(
1589 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1590 return flatSparseIndices;
1595 ShapedType type, DenseIntElementsAttr sparseIndices,
1596 DenseElementsAttr values) {
1597 ShapedType valuesType = values.
getType();
1598 if (valuesType.getRank() != 1)
1599 return emitError() <<
"expected 1-d tensor for sparse element values";
1602 ShapedType indicesType = sparseIndices.getType();
1603 auto emitShapeError = [&]() {
1604 return emitError() <<
"expected shape ([" << type.getShape()
1605 <<
"]); inferred shape of indices literal (["
1606 << indicesType.getShape()
1607 <<
"]); inferred shape of values literal (["
1608 << valuesType.getShape() <<
"])";
1611 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1612 if (indicesRank == 2) {
1613 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1614 return emitShapeError();
1615 }
else if (indicesRank != 1 || rank != 1) {
1616 return emitShapeError();
1619 int64_t numSparseIndices = indicesType.getDimSize(0);
1620 if (numSparseIndices != valuesType.getDimSize(0))
1621 return emitShapeError();
1624 auto emitIndexError = [&](
unsigned indexNum, ArrayRef<uint64_t> index) {
1626 <<
"sparse index #" << indexNum
1627 <<
" is not contained within the value shape, with index=[" << index
1628 <<
"], and type=" << type;
1632 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1633 if (sparseIndices.isSplat()) {
1634 SmallVector<uint64_t>
indices(rank, *sparseIndexValues.begin());
1635 if (!ElementsAttr::isValidIndex(type,
indices))
1636 return emitIndexError(0,
indices);
1641 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1642 ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1644 if (!ElementsAttr::isValidIndex(type, index))
1645 return emitIndexError(i, index);
1660 return getImpl()->referencedAttr;
1671 unsigned nSymbols = 0;
1675 if (ShapedType::isStatic(offset)) {
1685 for (
const auto &en : llvm::enumerate(strides)) {
1686 auto dim = en.index();
1687 auto stride = en.value();
1691 if (ShapedType::isStatic(stride))
1696 expr = expr + d * mult;
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 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 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 std::optional< NamedAttribute > findDuplicateElement(ArrayRef< NamedAttribute > value)
Returns an entry with a duplicate name from the given sorted array of named attributes.
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 isComplexOfIntType(Type type)
Return if the given complex type has an integer element type.
static Type getElementType(Type type)
Determine the element type of type.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
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.
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.
constexpr Attribute()=default
bool getValue() const
Return the boolean value of this attribute.
Attribute operator*() const
Accesses the Attribute value at this iterator position.
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
DenseElementsAttr resizeSplat(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but with a different ...
detail::ElementsAttrRange< IteratorT > iterator_range_impl
The iterator range over the given iterator type T.
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.
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Returns true if the given buffer is a valid raw buffer for the given type.
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.
constexpr Attribute()=default
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
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...
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.
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...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
static bool classof(Attribute attr)
Support for isa<>/cast<>.
ArrayRef< T > asArrayRef() const
void print(AsmPrinter &printer) const
Print the short form [42, 100, -1] without any type prefix.
static Attribute parse(AsmParser &parser, Type type)
Parse the short form [42, 100, -1] without any type prefix.
static Attribute parseWithoutBraces(AsmParser &parser, Type type)
Parse the short form 42, 100, -1 without any type prefix or braces.
void printWithoutBraces(raw_ostream &os) const
Print the short form 42, 100, -1 without any braces or type prefix.
Impl iterator for indexed DenseElementsAttr iterators that records a data pointer and data index that...
ptrdiff_t getDataIndex() const
const char * getData() const
Base class for DenseResourceElementsAttr that is instantiated and specialized for each supported elem...
static bool classof(Attribute attr)
Support for isa<>/cast<>.
static DenseResourceElementsAttrBase< T > get(ShapedType type, StringRef blobName, AsmResourceBlob blob)
A builder that inserts a new resource using the provided blob.
std::optional< ArrayRef< T > > tryGetAsArrayRef() const
Return the data of this attribute as an ArrayRef<T> if it is present, returns std::nullopt otherwise.
static ConcreteT get(MLIRContext *ctx, Args &&...args)
Get or create a new ConcreteT instance within the ctx.
ImplType * getImpl() const
llvm::APInt readBits(const char *rawData, size_t bitPos, size_t bitWidth)
Read bitWidth bits from byte-aligned position in rawData and return as an APInt.
size_t getDenseElementBitWidth(Type eltType)
Return the bit width which DenseElementsAttr should use for this type.
void writeBits(char *rawData, size_t bitPos, llvm::APInt value)
Write value to byte-aligned position bitPos in rawData.
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
DialectResourceBlobHandle< BuiltinDialect > DenseResourceElementsHandle
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.
llvm::function_ref< Fn > function_ref
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
static ManagerInterface & getManagerInterface(MLIRContext *ctx)
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object.
An attribute representing a reference to a dense vector or tensor object containing strings.