21#include "llvm/ADT/APSInt.h"
22#include "llvm/Support/Alignment.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/DebugLog.h"
25#include "llvm/Support/Endian.h"
28#define DEBUG_TYPE "builtinattributes"
37#define GET_ATTRDEF_CLASSES
38#include "mlir/IR/BuiltinAttributes.cpp.inc"
44void BuiltinDialect::registerAttributes() {
46#define GET_ATTRDEF_LIST
47#include "mlir/IR/BuiltinAttributes.cpp.inc"
49 addAttributes<DistinctAttr>();
60template <
bool inPlace>
64 switch (value.size()) {
73 storage.assign({value[0]});
76 bool isSorted = value[0] < value[1];
79 std::swap(storage[0], storage[1]);
80 }
else if (isSorted) {
81 storage.assign({value[0], value[1]});
83 storage.assign({value[1], value[0]});
89 storage.assign(value.begin(), value.end());
91 bool isSorted = llvm::is_sorted(value);
94 llvm::array_pod_sort(storage.begin(), storage.end());
102static std::optional<NamedAttribute>
104 const std::optional<NamedAttribute> none{std::nullopt};
105 if (value.size() < 2)
108 if (value.size() == 2)
109 return value[0].getName() == value[1].getName() ? value[0] : none;
111 const auto *it = std::adjacent_find(value.begin(), value.end(),
113 return l.getName() == r.getName();
115 return it != value.end() ? *it : none;
122 "DictionaryAttr element names must be unique");
129 "DictionaryAttr element names must be unique");
133std::optional<NamedAttribute>
141DictionaryAttr DictionaryAttr::get(
MLIRContext *context,
144 return DictionaryAttr::getEmpty(context);
147 SmallVector<NamedAttribute, 8> storage;
151 "DictionaryAttr element names must be unique");
152 return Base::get(context, value);
156DictionaryAttr DictionaryAttr::getWithSorted(
MLIRContext *context,
159 return DictionaryAttr::getEmpty(context);
161 assert(llvm::is_sorted(
162 value, [](NamedAttribute l, NamedAttribute r) {
return l < r; }) &&
163 "expected attribute values to be sorted");
165 "DictionaryAttr element names must be unique");
166 return Base::get(context, value);
170Attribute DictionaryAttr::get(StringRef name)
const {
171 auto it = impl::findAttrSorted(begin(), end(), name);
172 return it.second ? it.first->getValue() : Attribute();
174Attribute DictionaryAttr::get(StringAttr name)
const {
175 auto it = impl::findAttrSorted(begin(), end(), name);
176 return it.second ? it.first->getValue() : Attribute();
180std::optional<NamedAttribute> DictionaryAttr::getNamed(StringRef name)
const {
181 auto it = impl::findAttrSorted(begin(), end(), name);
182 return it.second ? *it.first : std::optional<NamedAttribute>();
184std::optional<NamedAttribute> DictionaryAttr::getNamed(StringAttr name)
const {
185 auto it = impl::findAttrSorted(begin(), end(), name);
186 return it.second ? *it.first : std::optional<NamedAttribute>();
190bool DictionaryAttr::contains(StringRef name)
const {
191 return impl::findAttrSorted(begin(), end(), name).second;
193bool DictionaryAttr::contains(StringAttr name)
const {
194 return impl::findAttrSorted(begin(), end(), name).second;
197DictionaryAttr::iterator DictionaryAttr::begin()
const {
198 return getValue().begin();
200DictionaryAttr::iterator DictionaryAttr::end()
const {
201 return getValue().end();
203size_t DictionaryAttr::size()
const {
return getValue().size(); }
205DictionaryAttr DictionaryAttr::getEmptyUnchecked(
MLIRContext *context) {
206 return Base::get(context, ArrayRef<NamedAttribute>());
214void StridedLayoutAttr::print(llvm::raw_ostream &os)
const {
215 auto printIntOrQuestion = [&](
int64_t value) {
216 if (ShapedType::isDynamic(value))
223 llvm::interleaveComma(getStrides(), os, printIntOrQuestion);
226 if (getOffset() != 0) {
228 printIntOrQuestion(getOffset());
235bool StridedLayoutAttr::hasStaticLayout()
const {
236 return ShapedType::isStatic(getOffset()) &&
237 ShapedType::isStaticShape(getStrides());
241AffineMap StridedLayoutAttr::getAffineMap()
const {
253LogicalResult StridedLayoutAttr::verifyLayout(
256 if (
shape.size() != getStrides().size())
257 return emitError() <<
"expected the number of strides to match the rank";
266 llvm::append_range(strides, getStrides());
267 offset = getOffset();
275StringAttr StringAttr::getEmptyStringAttrUnchecked(
MLIRContext *context) {
276 return Base::get(context,
"", NoneType::get(context));
280StringAttr StringAttr::get(
MLIRContext *context,
const Twine &twine) {
282 if (twine.isTriviallyEmpty())
284 SmallVector<char, 32> tempStr;
285 return Base::get(context, twine.toStringRef(tempStr), NoneType::get(context));
289StringAttr StringAttr::get(
const Twine &twine,
Type type) {
290 SmallVector<char, 32> tempStr;
291 return Base::get(type.
getContext(), twine.toStringRef(tempStr), type);
294StringRef StringAttr::getValue()
const {
return getImpl()->value; }
296Type StringAttr::getType()
const {
return getImpl()->type; }
298Dialect *StringAttr::getReferencedDialect()
const {
299 return getImpl()->referencedDialect;
306double FloatAttr::getValueAsDouble()
const {
307 return getValueAsDouble(getValue());
309double FloatAttr::getValueAsDouble(APFloat value) {
310 if (&value.getSemantics() != &APFloat::IEEEdouble()) {
311 bool losesInfo =
false;
312 value.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven,
315 return value.convertToDouble();
319 Type type, APFloat value) {
321 if (!llvm::isa<FloatType>(type))
322 return emitError() <<
"expected floating point type";
325 if (&llvm::cast<FloatType>(type).getFloatSemantics() !=
326 &value.getSemantics()) {
328 <<
"FloatAttr type doesn't match the type implied by its value";
337SymbolRefAttr SymbolRefAttr::get(
MLIRContext *ctx, StringRef value,
339 return get(StringAttr::get(ctx, value), nestedRefs);
343 return llvm::cast<FlatSymbolRefAttr>(
get(ctx, value, {}));
347 return llvm::cast<FlatSymbolRefAttr>(
get(value, {}));
353 assert(symName &&
"value does not have a valid symbol name");
354 return SymbolRefAttr::get(symName);
357StringAttr SymbolRefAttr::getLeafReference()
const {
358 ArrayRef<FlatSymbolRefAttr> nestedRefs = getNestedReferences();
359 return nestedRefs.empty() ? getRootReference() : nestedRefs.back().getAttr();
366int64_t IntegerAttr::getInt()
const {
368 "must be signless integer");
369 return getValue().getSExtValue();
372int64_t IntegerAttr::getSInt()
const {
373 assert(
getType().isSignedInteger() &&
"must be signed integer");
374 return getValue().getSExtValue();
377uint64_t IntegerAttr::getUInt()
const {
378 assert(
getType().isUnsignedInteger() &&
"must be unsigned integer");
379 return getValue().getZExtValue();
384APSInt IntegerAttr::getAPSInt()
const {
385 assert(!
getType().isSignlessInteger() &&
386 "Signless integers don't carry a sign for APSInt");
387 return APSInt(getValue(),
getType().isUnsignedInteger());
391 Type type, APInt value) {
392 if (IntegerType integerType = llvm::dyn_cast<IntegerType>(type)) {
393 if (integerType.getWidth() != value.getBitWidth())
394 return emitError() <<
"integer type bit width (" << integerType.getWidth()
395 <<
") doesn't match value bit width ("
396 << value.getBitWidth() <<
")";
399 if (llvm::isa<IndexType>(type)) {
400 if (value.getBitWidth() != IndexType::kInternalStorageBitWidth)
402 <<
"value bit width (" << value.getBitWidth()
403 <<
") doesn't match index type internal storage bit width ("
404 << IndexType::kInternalStorageBitWidth <<
")";
407 return emitError() <<
"expected integer or index type";
410BoolAttr IntegerAttr::getBoolAttrUnchecked(IntegerType type,
bool value) {
411 auto attr = Base::get(type.getContext(), type, APInt(1, value));
412 return llvm::cast<BoolAttr>(attr);
420 auto *storage =
reinterpret_cast<IntegerAttrStorage *
>(
impl);
421 return storage->value.getBoolValue();
425 IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr);
426 return intAttr && intAttr.getType().isSignlessInteger(1);
434 StringAttr dialect, StringRef attrData,
437 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
444 <<
"#" << dialect <<
"<\"" << attrData <<
"\"> : " << type
445 <<
" attribute created with unregistered dialect. If this is "
446 "intended, please call allowUnregisteredDialects() on the "
447 "MLIRContext, or use -allow-unregistered-dialect with "
448 "the MLIR opt tool used";
461 return llvm::alignTo<8>(origWidth);
471 assert(llvm::endianness::native == llvm::endianness::big);
472 assert(value.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
477 size_t numFilledWords = (value.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
478 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
483 size_t lastWordPos = numFilledWords;
485 DenseTypedElementsAttr::convertEndianOfCharForBEmachine(
486 reinterpret_cast<const char *
>(value.getRawData()) + lastWordPos,
487 valueLE.begin(), APInt::APINT_BITS_PER_WORD, 1);
491 DenseTypedElementsAttr::convertEndianOfCharForBEmachine(
492 valueLE.begin(),
result + lastWordPos,
493 (numBytes - lastWordPos) * CHAR_BIT, 1);
500 assert(llvm::endianness::native == llvm::endianness::big);
501 assert(
result.getNumWords() * APInt::APINT_WORD_SIZE >= numBytes);
508 size_t numFilledWords = (
result.getNumWords() - 1) * APInt::APINT_WORD_SIZE;
510 inArray, numFilledWords,
511 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())));
516 size_t lastWordPos = numFilledWords;
518 DenseTypedElementsAttr::convertEndianOfCharForBEmachine(
519 inArray + lastWordPos, inArrayLE.begin(),
520 (numBytes - lastWordPos) * CHAR_BIT, 1);
524 DenseTypedElementsAttr::convertEndianOfCharForBEmachine(
526 const_cast<char *
>(
reinterpret_cast<const char *
>(
result.getRawData())) +
528 APInt::APINT_BITS_PER_WORD, 1);
533 size_t bitWidth = value.getBitWidth();
536 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
537 if (llvm::endianness::native == llvm::endianness::big) {
544 rawData + (bitPos / CHAR_BIT));
546 std::copy_n(
reinterpret_cast<const char *
>(value.getRawData()),
547 llvm::divideCeil(bitWidth, CHAR_BIT),
548 rawData + (bitPos / CHAR_BIT));
557 assert((bitPos % CHAR_BIT) == 0 &&
"expected bitPos to be 8-bit aligned");
558 APInt
result(bitWidth, 0);
559 if (llvm::endianness::native == llvm::endianness::big) {
566 llvm::divideCeil(bitWidth, CHAR_BIT),
result);
568 std::copy_n(rawData + (bitPos / CHAR_BIT),
569 llvm::divideCeil(bitWidth, CHAR_BIT),
571 reinterpret_cast<const char *
>(
result.getRawData())));
578template <
typename Values>
580 return (values.size() == 1) ||
581 (type.getNumElements() ==
static_cast<int64_t>(values.size()));
592DenseElementsAttr::AttributeElementIterator::AttributeElementIterator(
594 : llvm::indexed_accessor_iterator<AttributeElementIterator, const void *,
596 attr.getAsOpaquePointer(),
index) {}
600 Type eltTy = owner.getElementType();
603 if (llvm::isa<DenseStringElementsAttr>(owner)) {
605 return StringAttr::get(owner.isSplat() ? vals.front() : vals[
index], eltTy);
609 auto denseEltTy = llvm::cast<DenseElementType>(eltTy);
612 size_t bitSize = denseEltTy.getDenseElementBitSize();
613 size_t byteSize = llvm::divideCeil(bitSize, CHAR_BIT);
614 size_t offset = owner.isSplat() ? 0 :
index * byteSize;
615 return denseEltTy.convertToAttribute(rawData.slice(offset, byteSize));
622DenseElementsAttr::BoolElementIterator::BoolElementIterator(
635DenseElementsAttr::IntElementIterator::IntElementIterator(
651DenseElementsAttr::ComplexIntElementIterator::ComplexIntElementIterator(
657 auto complexType = llvm::cast<ComplexType>(attr.
getElementType());
677 return emitError() <<
"expected integer or floating point element type";
678 int64_t dataSize = rawData.size();
681 if (
size * elementSize != dataSize) {
682 return emitError() <<
"expected data size (" <<
size <<
" elements, "
684 <<
" bytes each) does not match: " << dataSize
693template <
size_t width,
694 IntegerType::SignednessSemantics signedness = IntegerType::Signless>
695struct DenseArrayAttrIntUtil {
696 static bool checkElementType(
Type eltType) {
697 auto type = llvm::dyn_cast<IntegerType>(eltType);
698 if (!type || type.getWidth() != width)
700 return type.getSignedness() == signedness;
704 return IntegerType::get(ctx, width, signedness);
707 template <
typename T>
708 static void printElement(raw_ostream &os, T value) {
712 template <
typename T>
713 static ParseResult parseElement(AsmParser &parser, T &value) {
718struct DenseArrayAttrUtil;
723struct DenseArrayAttrUtil<bool> :
public DenseArrayAttrIntUtil<1> {
724 static void printElement(raw_ostream &os,
bool value) {
725 os << (value ?
"true" :
"false");
732struct DenseArrayAttrUtil<int8_t> :
public DenseArrayAttrIntUtil<8> {
733 static void printElement(
raw_ostream &os, int8_t value) {
734 os << static_cast<int>(value);
738struct DenseArrayAttrUtil<int16_t> :
public DenseArrayAttrIntUtil<16> {};
740struct DenseArrayAttrUtil<int32_t> :
public DenseArrayAttrIntUtil<32> {};
742struct DenseArrayAttrUtil<int64_t> :
public DenseArrayAttrIntUtil<64> {};
746struct DenseArrayAttrUtil<float> {
747 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
748 static Type
getElementType(MLIRContext *ctx) {
return Float32Type::get(ctx); }
749 static void printElement(raw_ostream &os,
float value) { os << value; }
752 static ParseResult parseElement(AsmParser &parser,
float &value) {
763struct DenseArrayAttrUtil<double> {
764 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
765 static Type
getElementType(MLIRContext *ctx) {
return Float64Type::get(ctx); }
766 static void printElement(raw_ostream &os,
float value) { os << value; }
767 static ParseResult parseElement(AsmParser &parser,
double &value) {
780 llvm::interleaveComma(
asArrayRef(), os, [&](T value) {
781 DenseArrayAttrUtil<T>::printElement(os, value);
799 if (DenseArrayAttrUtil<T>::parseElement(parser, value))
801 data.push_back(value);
826 assert(llvm::isAddrAligned(llvm::Align(
alignof(T)), raw.data()));
827 assert((raw.size() %
sizeof(T)) == 0);
828 return ArrayRef<T>(
reinterpret_cast<const T *
>(raw.data()),
829 raw.size() /
sizeof(T));
836 Type elementType = DenseArrayAttrUtil<T>::getElementType(context);
837 auto rawArray =
ArrayRef<char>(
reinterpret_cast<const char *
>(content.data()),
838 content.size() *
sizeof(T));
839 return llvm::cast<DenseArrayAttrImpl<T>>(
840 Base::get(context, elementType, content.size(), rawArray));
845 if (
auto denseArray = llvm::dyn_cast<DenseArrayAttr>(attr))
846 return DenseArrayAttrUtil<T>::checkElementType(denseArray.getElementType());
869 return llvm::isa<DenseTypedElementsAttr, DenseStringElementsAttr>(attr);
875 Type eltType = type.getElementType();
878 if (!llvm::isa<DenseElementType>(eltType)) {
880 stringValues.reserve(values.size());
882 assert(llvm::isa<StringAttr>(attr) &&
883 "expected string value for non-DenseElementType element");
884 stringValues.push_back(llvm::cast<StringAttr>(attr).getValue());
886 return get(type, stringValues);
890 auto denseEltType = llvm::dyn_cast<DenseElementType>(eltType);
891 assert(denseEltType &&
892 "attempted to get DenseElementsAttr with unsupported element type");
895 LogicalResult
result = denseEltType.convertFromAttribute(attr, data);
899 return DenseTypedElementsAttr::getRaw(type, data);
905 assert(type.getElementType().isInteger(1));
906 return DenseTypedElementsAttr::getRaw(
907 type,
ArrayRef<char>(
reinterpret_cast<const char *
>(values.data()),
913 assert(!type.getElementType().isIntOrFloat());
914 return DenseStringElementsAttr::get(type, values);
922 assert(type.getElementType().isIntOrIndex());
925 return DenseTypedElementsAttr::getRaw(type, storageBitWidth, values);
929 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
930 assert(llvm::isa<IntegerType>(
complex.getElementType()));
933 ArrayRef<APInt> intVals(
reinterpret_cast<const APInt *
>(values.data()),
935 return DenseTypedElementsAttr::getRaw(type, storageBitWidth, intVals);
943 assert(llvm::isa<FloatType>(type.getElementType()));
946 return DenseTypedElementsAttr::getRaw(type, storageBitWidth, values);
951 ComplexType
complex = llvm::cast<ComplexType>(type.getElementType());
952 assert(llvm::isa<FloatType>(
complex.getElementType()));
957 return DenseTypedElementsAttr::getRaw(type, storageBitWidth, apVals);
965 return DenseTypedElementsAttr::getRaw(type, rawBuffer);
972 size_t rawBufferWidth = rawBuffer.size() * CHAR_BIT;
973 int64_t numElements = type.getNumElements();
977 return rawBufferWidth == storageWidth ||
978 rawBufferWidth == storageWidth * numElements;
988 auto dataSize =
static_cast<size_t>(dataEltSize * CHAR_BIT);
989 if (denseEltBitWidth != dataSize) {
990 LDBG() <<
"expected dense element bit width " << denseEltBitWidth
991 <<
" to match data size " << dataSize <<
" for type " << type;
997 bool valid = llvm::isa<FloatType>(type);
999 LDBG() <<
"expected float type when isInt is false, but found " << type;
1005 auto intType = llvm::dyn_cast<IntegerType>(type);
1007 LDBG() <<
"expected integer type when isInt is true, but found " << type;
1012 if (intType.isSignless())
1015 bool valid = intType.isSigned() == isSigned;
1017 LDBG() <<
"expected signedness " << isSigned <<
" to match type " << type;
1025 bool isInt,
bool isSigned) {
1026 return DenseTypedElementsAttr::getRawComplex(type, data, dataEltSize, isInt,
1034 return DenseTypedElementsAttr::getRawIntOrFloat(type, data, dataEltSize,
1039 bool isSigned)
const {
1040 return ::isValidIntOrFloat(
getElementType(), dataEltSize, isInt, isSigned);
1043 bool isSigned)
const {
1044 return ::isValidIntOrFloat(
1046 dataEltSize / 2, isInt, isSigned);
1053 if (isa<DenseStringElementsAttr>(*
this))
1056 size_t storageSize = llvm::divideCeil(
1063 return llvm::isa<IntegerType>(llvm::cast<ComplexType>(type).
getElementType());
1080 const auto &elementSemantics = eltTy.getFloatSemantics();
1091 auto eltTy = llvm::dyn_cast<FloatType>(complexTy.getElementType());
1094 const auto &semantics = eltTy.getFloatSemantics();
1096 getType(), {semantics, {*
this, 0}},
1113 ShapedType curType =
getType();
1114 if (curType == newType)
1117 assert(newType.getElementType() == curType.getElementType() &&
1118 "expected the same element type");
1119 assert(newType.getNumElements() == curType.getNumElements() &&
1120 "expected the same number of elements");
1121 return DenseTypedElementsAttr::getRaw(newType,
getRawData());
1125 assert(
isSplat() &&
"expected a splat type");
1127 ShapedType curType =
getType();
1128 if (curType == newType)
1131 assert(newType.getElementType() == curType.getElementType() &&
1132 "expected the same element type");
1133 return DenseTypedElementsAttr::getRaw(newType,
getRawData());
1141 ShapedType curType =
getType();
1142 Type curElType = curType.getElementType();
1143 if (curElType == newElType)
1148 "expected element types with the same bitwidth");
1149 return DenseTypedElementsAttr::getRaw(curType.clone(newElType),
getRawData());
1155 return llvm::cast<DenseIntElementsAttr>(*this).
mapValues(newElementType,
1161 return llvm::cast<DenseFPElementsAttr>(*this).
mapValues(newElementType,
1170 return getType().getElementType();
1174 return getType().getNumElements();
1182template <
typename APRangeT>
1185 APRangeT &&values) {
1186 size_t numValues = llvm::size(values);
1187 data.resize(llvm::divideCeil(storageWidth * numValues, CHAR_BIT));
1189 for (
auto it = values.begin(), e = values.end(); it != e;
1190 ++it, offset += storageWidth) {
1191 assert((*it).getBitWidth() <= storageWidth);
1199DenseElementsAttr DenseTypedElementsAttr::getRaw(ShapedType type,
1200 size_t storageWidth,
1201 ArrayRef<APFloat> values) {
1202 SmallVector<char> data;
1203 auto unwrapFloat = [](
const APFloat &val) {
return val.bitcastToAPInt(); };
1205 return DenseTypedElementsAttr::getRaw(type, data);
1211DenseElementsAttr DenseTypedElementsAttr::getRaw(ShapedType type,
1212 size_t storageWidth,
1213 ArrayRef<APInt> values) {
1214 SmallVector<char> data;
1216 return DenseTypedElementsAttr::getRaw(type, data);
1219DenseElementsAttr DenseTypedElementsAttr::getRaw(ShapedType type,
1220 ArrayRef<char> data) {
1221 assert(type.hasStaticShape() &&
"type must have static shape");
1222 assert(isValidRawBuffer(type, data));
1223 return Base::get(type.getContext(), type, data);
1229DenseElementsAttr DenseTypedElementsAttr::getRawComplex(ShapedType type,
1230 ArrayRef<char> data,
1231 int64_t dataEltSize,
1235 llvm::cast<ComplexType>(type.getElementType()).getElementType(),
1236 dataEltSize / 2, isInt, isSigned) &&
1237 "Try re-running with -debug-only=builtinattributes");
1239 int64_t numElements = data.size() / dataEltSize;
1241 assert(numElements == 1 || numElements == type.getNumElements());
1242 return getRaw(type, data);
1248DenseElementsAttr DenseTypedElementsAttr::getRawIntOrFloat(ShapedType type,
1249 ArrayRef<char> data,
1250 int64_t dataEltSize,
1255 "Try re-running with -debug-only=builtinattributes");
1257 int64_t numElements = data.size() / dataEltSize;
1258 assert(numElements == 1 || numElements == type.getNumElements());
1260 return getRaw(type, data);
1263void DenseTypedElementsAttr::convertEndianOfCharForBEmachine(
1264 const char *inRawData,
char *outRawData,
size_t elementBitWidth,
1265 size_t numElements) {
1266 using llvm::support::ulittle16_t;
1267 using llvm::support::ulittle32_t;
1268 using llvm::support::ulittle64_t;
1270 assert(llvm::endianness::native == llvm::endianness::big);
1274 switch (elementBitWidth) {
1276 const ulittle16_t *inRawDataPos =
1277 reinterpret_cast<const ulittle16_t *
>(inRawData);
1278 uint16_t *outDataPos =
reinterpret_cast<uint16_t *
>(outRawData);
1279 std::copy_n(inRawDataPos, numElements, outDataPos);
1283 const ulittle32_t *inRawDataPos =
1284 reinterpret_cast<const ulittle32_t *
>(inRawData);
1285 uint32_t *outDataPos =
reinterpret_cast<uint32_t *
>(outRawData);
1286 std::copy_n(inRawDataPos, numElements, outDataPos);
1290 const ulittle64_t *inRawDataPos =
1291 reinterpret_cast<const ulittle64_t *
>(inRawData);
1292 uint64_t *outDataPos =
reinterpret_cast<uint64_t *
>(outRawData);
1293 std::copy_n(inRawDataPos, numElements, outDataPos);
1297 size_t nBytes = elementBitWidth / CHAR_BIT;
1298 for (
size_t i = 0; i < nBytes; i++)
1299 std::copy_n(inRawData + (nBytes - 1 - i), 1, outRawData + i);
1305void DenseTypedElementsAttr::convertEndianOfArrayRefForBEmachine(
1306 ArrayRef<char> inRawData, MutableArrayRef<char> outRawData,
1308 size_t numElements = type.getNumElements();
1309 Type elementType = type.getElementType();
1310 if (ComplexType complexTy = llvm::dyn_cast<ComplexType>(elementType)) {
1311 elementType = complexTy.getElementType();
1312 numElements = numElements * 2;
1315 assert(numElements * elementBitWidth == inRawData.size() * CHAR_BIT &&
1316 inRawData.size() <= outRawData.size());
1317 if (elementBitWidth <= CHAR_BIT)
1318 std::memcpy(outRawData.begin(), inRawData.begin(), inRawData.size());
1320 convertEndianOfCharForBEmachine(inRawData.begin(), outRawData.begin(),
1321 elementBitWidth, numElements);
1328template <
typename Fn,
typename Attr>
1330 Type newElementType,
1335 ShapedType newArrayType = inType.cloneWith(inType.getShape(), newElementType);
1337 size_t numRawElements = attr.isSplat() ? 1 : newArrayType.getNumElements();
1338 data.resize(llvm::divideCeil(storageBitWidth * numRawElements, CHAR_BIT));
1341 auto processElt = [&](
decltype(*attr.begin()) value,
size_t index) {
1342 auto newInt = mapping(value);
1343 assert(newInt.getBitWidth() == bitWidth);
1348 if (attr.isSplat()) {
1349 processElt(*attr.begin(), 0);
1350 return newArrayType;
1354 uint64_t elementIdx = 0;
1355 for (
auto value : attr)
1356 processElt(value, elementIdx++);
1357 return newArrayType;
1366 return getRaw(newArrayType, elementData);
1371 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1372 return llvm::isa<FloatType>(denseAttr.getType().getElementType());
1385 return getRaw(newArrayType, elementData);
1390 if (
auto denseAttr = llvm::dyn_cast<DenseElementsAttr>(attr))
1391 return denseAttr.getType().getElementType().isIntOrIndex();
1399DenseResourceElementsAttr
1400DenseResourceElementsAttr::get(ShapedType type,
1402 return Base::get(type.getContext(), type, handle);
1405DenseResourceElementsAttr DenseResourceElementsAttr::get(ShapedType type,
1412 return get(type, manager.insert(blobName, std::move(blob)));
1415ArrayRef<char> DenseResourceElementsAttr::getData() {
1416 if (AsmResourceBlob *blob = this->getRawHandle().getBlob())
1417 return blob->getDataAs<
char>();
1428template <
typename T>
1429struct DenseResourceAttrUtil;
1430template <
size_t w
idth,
bool isSigned>
1431struct DenseResourceElementsAttrIntUtil {
1432 static bool checkElementType(Type eltType) {
1433 IntegerType type = llvm::dyn_cast<IntegerType>(eltType);
1434 if (!type || type.getWidth() != width)
1436 return isSigned ? !type.isUnsigned() : !type.isSigned();
1440struct DenseResourceAttrUtil<bool> {
1441 static bool checkElementType(Type eltType) {
1446struct DenseResourceAttrUtil<int8_t>
1447 :
public DenseResourceElementsAttrIntUtil<8, true> {};
1449struct DenseResourceAttrUtil<uint8_t>
1450 :
public DenseResourceElementsAttrIntUtil<8, false> {};
1452struct DenseResourceAttrUtil<int16_t>
1453 :
public DenseResourceElementsAttrIntUtil<16, true> {};
1455struct DenseResourceAttrUtil<uint16_t>
1456 :
public DenseResourceElementsAttrIntUtil<16, false> {};
1458struct DenseResourceAttrUtil<int32_t>
1459 :
public DenseResourceElementsAttrIntUtil<32, true> {};
1461struct DenseResourceAttrUtil<uint32_t>
1462 :
public DenseResourceElementsAttrIntUtil<32, false> {};
1464struct DenseResourceAttrUtil<int64_t>
1465 :
public DenseResourceElementsAttrIntUtil<64, true> {};
1467struct DenseResourceAttrUtil<uint64_t>
1468 :
public DenseResourceElementsAttrIntUtil<64, false> {};
1470struct DenseResourceAttrUtil<float> {
1471 static bool checkElementType(Type eltType) {
return eltType.
isF32(); }
1474struct DenseResourceAttrUtil<double> {
1475 static bool checkElementType(Type eltType) {
return eltType.
isF64(); }
1479template <
typename T>
1480DenseResourceElementsAttrBase<T>
1485 "alignment mismatch between expected alignment and blob alignment");
1486 assert(((blob.
getData().size() %
sizeof(T)) == 0) &&
1487 "size mismatch between expected element width and blob size");
1488 assert(DenseResourceAttrUtil<T>::checkElementType(type.getElementType()) &&
1489 "invalid shape element type for provided type `T`");
1490 return llvm::cast<DenseResourceElementsAttrBase<T>>(
1491 DenseResourceElementsAttr::get(type, blobName, std::move(blob)));
1494template <
typename T>
1495std::optional<ArrayRef<T>>
1498 return blob->template getDataAs<T>();
1499 return std::nullopt;
1502template <
typename T>
1504 auto resourceAttr = llvm::dyn_cast<DenseResourceElementsAttr>(attr);
1505 return resourceAttr && DenseResourceAttrUtil<T>::checkElementType(
1506 resourceAttr.getElementType());
1531APFloat SparseElementsAttr::getZeroAPFloat()
const {
1533 return APFloat(eltType.getFloatSemantics());
1537APInt SparseElementsAttr::getZeroAPInt()
const {
1539 return APInt::getZero(eltType.getWidth());
1543Attribute SparseElementsAttr::getZeroAttr()
const {
1547 if (llvm::isa<FloatType>(eltType))
1548 return FloatAttr::get(eltType, 0);
1551 if (
auto complexTy = llvm::dyn_cast<ComplexType>(eltType)) {
1552 auto eltType = complexTy.getElementType();
1554 if (llvm::isa<FloatType>(eltType))
1555 zero = FloatAttr::get(eltType, 0);
1557 zero = IntegerAttr::get(eltType, 0);
1558 return ArrayAttr::get(complexTy.getContext(),
1559 ArrayRef<Attribute>{zero, zero});
1563 if (llvm::isa<DenseStringElementsAttr>(getValues()))
1564 return StringAttr::get(
"", eltType);
1567 return IntegerAttr::get(eltType, 0);
1572SmallVector<ptrdiff_t> SparseElementsAttr::getFlattenedSparseIndices()
const {
1573 SmallVector<ptrdiff_t> flatSparseIndices;
1578 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1579 if (sparseIndices.isSplat()) {
1581 *sparseIndexValues.begin());
1582 flatSparseIndices.push_back(getFlattenedIndex(
indices));
1583 return flatSparseIndices;
1587 auto numSparseIndices = sparseIndices.getType().getDimSize(0);
1588 size_t rank =
getType().getRank();
1589 for (
size_t i = 0, e = numSparseIndices; i != e; ++i)
1590 flatSparseIndices.push_back(getFlattenedIndex(
1591 {&*std::next(sparseIndexValues.begin(), i * rank), rank}));
1592 return flatSparseIndices;
1597 ShapedType type, DenseIntElementsAttr sparseIndices,
1598 DenseElementsAttr values) {
1599 ShapedType valuesType = values.
getType();
1600 if (valuesType.getRank() != 1)
1601 return emitError() <<
"expected 1-d tensor for sparse element values";
1604 ShapedType indicesType = sparseIndices.getType();
1605 auto emitShapeError = [&]() {
1606 return emitError() <<
"expected shape ([" << type.getShape()
1607 <<
"]); inferred shape of indices literal (["
1608 << indicesType.getShape()
1609 <<
"]); inferred shape of values literal (["
1610 << valuesType.getShape() <<
"])";
1613 size_t rank = type.getRank(), indicesRank = indicesType.getRank();
1614 if (indicesRank == 2) {
1615 if (indicesType.getDimSize(1) !=
static_cast<int64_t
>(rank))
1616 return emitShapeError();
1617 }
else if (indicesRank != 1 || rank != 1) {
1618 return emitShapeError();
1621 int64_t numSparseIndices = indicesType.getDimSize(0);
1622 if (numSparseIndices != valuesType.getDimSize(0))
1623 return emitShapeError();
1626 auto emitIndexError = [&](
unsigned indexNum, ArrayRef<uint64_t> index) {
1628 <<
"sparse index #" << indexNum
1629 <<
" is not contained within the value shape, with index=[" << index
1630 <<
"], and type=" << type;
1634 auto sparseIndexValues = sparseIndices.getValues<uint64_t>();
1635 if (sparseIndices.isSplat()) {
1636 SmallVector<uint64_t>
indices(rank, *sparseIndexValues.begin());
1637 if (!ElementsAttr::isValidIndex(type,
indices))
1638 return emitIndexError(0,
indices);
1643 for (
size_t i = 0, e = numSparseIndices; i != e; ++i) {
1644 ArrayRef<uint64_t> index(&*std::next(sparseIndexValues.begin(), i * rank),
1646 if (!ElementsAttr::isValidIndex(type, index))
1647 return emitIndexError(i, index);
1662 return getImpl()->referencedAttr;
1673 unsigned nSymbols = 0;
1677 if (ShapedType::isStatic(offset)) {
1687 for (
const auto &en : llvm::enumerate(strides)) {
1688 auto dim = en.index();
1689 auto stride = en.value();
1693 if (ShapedType::isStatic(stride))
1698 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.
mlir::Complex< APInt > operator*() const
Accesses the raw mlir::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.
std::conditional_t< std::is_floating_point_v< T >, std::complex< T >, NonFloatComplex< T > > Complex
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 containing strings.
An attribute representing a reference to a dense vector or tensor object.