18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/CachedHashString.h"
20 #include "llvm/ADT/MapVector.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/raw_ostream.h"
26 #define DEBUG_TYPE "mlir-bytecode-writer"
36 Impl(StringRef producer) : producer(producer) {}
44 bool shouldElideResourceData =
false;
63 :
impl(std::make_unique<
Impl>(producer)) {}
73 return impl->attributeWriterCallbacks;
78 return impl->typeWriterCallbacks;
83 impl->attributeWriterCallbacks.emplace_back(std::move(callback));
88 impl->typeWriterCallbacks.emplace_back(std::move(callback));
92 std::unique_ptr<AsmResourcePrinter> printer) {
93 impl->externalResourcePrinters.emplace_back(std::move(printer));
97 bool shouldElideResourceData) {
98 impl->shouldElideResourceData = shouldElideResourceData;
102 impl->bytecodeVersion = bytecodeVersion;
106 return impl->bytecodeVersion;
109 llvm::StringMap<std::unique_ptr<DialectVersion>> &
111 return impl->dialectVersionMap;
115 llvm::StringRef dialectName,
116 std::unique_ptr<DialectVersion> dialectVersion)
const {
117 assert(!
impl->dialectVersionMap.contains(dialectName) &&
118 "cannot override a previously set dialect version");
119 impl->dialectVersionMap.insert({dialectName, std::move(dialectVersion)});
132 class EncodingEmitter {
134 EncodingEmitter() =
default;
135 EncodingEmitter(
const EncodingEmitter &) =
delete;
136 EncodingEmitter &operator=(
const EncodingEmitter &) =
delete;
139 void writeTo(raw_ostream &os)
const;
142 size_t size()
const {
return prevResultSize + currentResult.size(); }
149 void patchByte(uint64_t offset, uint8_t value) {
150 assert(offset < size() && offset >= prevResultSize &&
151 "cannot patch previously emitted data");
152 currentResult[offset - prevResultSize] = value;
159 appendResult(std::move(currentResult));
160 appendOwnedResult(data);
168 emitVarInt(alignment);
169 emitVarInt(data.size());
174 void emitOwnedBlobAndAlignment(
ArrayRef<char> data, uint32_t alignment) {
177 emitOwnedBlobAndAlignment(castedData, alignment);
181 void alignTo(
unsigned alignment) {
184 assert(llvm::isPowerOf2_32(alignment) &&
"expected valid alignment");
188 size_t curOffset = size();
189 size_t paddingSize = llvm::alignTo(curOffset, alignment) - curOffset;
190 while (paddingSize--)
194 requiredAlignment =
std::max(requiredAlignment, alignment);
201 template <
typename T>
202 void emitByte(T
byte) {
203 currentResult.push_back(
static_cast<uint8_t
>(
byte));
208 llvm::append_range(currentResult, bytes);
218 void emitVarInt(uint64_t value) {
221 if ((value >> 7) == 0)
222 return emitByte((value << 1) | 0x1);
223 emitMultiByteVarInt(value);
230 void emitSignedVarInt(uint64_t value) {
231 emitVarInt((value << 1) ^ (uint64_t)((int64_t)value >> 63));
236 void emitVarIntWithFlag(uint64_t value,
bool flag) {
237 emitVarInt((value << 1) | (flag ? 1 : 0));
244 void emitNulTerminatedString(StringRef str) {
250 void emitString(StringRef str) {
251 emitBytes({
reinterpret_cast<const uint8_t *
>(str.data()), str.size()});
263 uint64_t codeOffset = currentResult.size();
265 emitVarInt(emitter.size());
268 unsigned emitterAlign = emitter.requiredAlignment;
269 if (emitterAlign > 1) {
270 if (size() & (emitterAlign - 1)) {
271 emitVarInt(emitterAlign);
272 alignTo(emitterAlign);
276 currentResult[codeOffset] |= 0b10000000;
280 requiredAlignment =
std::max(requiredAlignment, emitterAlign);
286 appendResult(std::move(currentResult));
287 for (std::vector<uint8_t> &result : emitter.prevResultStorage)
288 prevResultStorage.push_back(std::move(result));
289 llvm::append_range(prevResultList, emitter.prevResultList);
290 prevResultSize += emitter.prevResultSize;
291 appendResult(std::move(emitter.currentResult));
299 LLVM_ATTRIBUTE_NOINLINE
void emitMultiByteVarInt(uint64_t value);
302 void appendResult(std::vector<uint8_t> &&result) {
305 prevResultStorage.emplace_back(std::move(result));
306 appendOwnedResult(prevResultStorage.back());
311 prevResultSize += result.size();
312 prevResultList.emplace_back(result);
320 std::vector<uint8_t> currentResult;
321 std::vector<ArrayRef<uint8_t>> prevResultList;
322 std::vector<std::vector<uint8_t>> prevResultStorage;
326 size_t prevResultSize = 0;
329 unsigned requiredAlignment = 1;
338 class StringSectionBuilder {
342 size_t insert(StringRef str) {
343 auto it = strings.insert({llvm::CachedHashStringRef(str), strings.size()});
344 return it.first->second;
348 void write(EncodingEmitter &emitter) {
349 emitter.emitVarInt(strings.size());
353 for (
const auto &it : llvm::reverse(strings))
354 emitter.emitVarInt(it.first.size() + 1);
356 for (
const auto &it : strings)
357 emitter.emitNulTerminatedString(it.first.val());
363 llvm::MapVector<llvm::CachedHashStringRef, size_t> strings;
368 using DialectVersionMapT = llvm::StringMap<std::unique_ptr<DialectVersion>>;
371 DialectWriter(int64_t bytecodeVersion, EncodingEmitter &emitter,
373 StringSectionBuilder &stringSection,
374 const DialectVersionMapT &dialectVersionMap)
375 : bytecodeVersion(bytecodeVersion), emitter(emitter),
376 numberingState(numberingState), stringSection(stringSection),
377 dialectVersionMap(dialectVersionMap) {}
383 void writeAttribute(
Attribute attr)
override {
384 emitter.emitVarInt(numberingState.getNumber(attr));
386 void writeOptionalAttribute(
Attribute attr)
override {
388 emitter.emitVarInt(0);
391 emitter.emitVarIntWithFlag(numberingState.getNumber(attr),
true);
394 void writeType(
Type type)
override {
395 emitter.emitVarInt(numberingState.getNumber(type));
399 emitter.emitVarInt(numberingState.getNumber(resource));
406 void writeVarInt(uint64_t value)
override { emitter.emitVarInt(value); }
408 void writeSignedVarInt(int64_t value)
override {
409 emitter.emitSignedVarInt(value);
412 void writeAPIntWithKnownWidth(
const APInt &value)
override {
413 size_t bitWidth = value.getBitWidth();
418 return emitter.emitByte(value.getLimitedValue());
422 return emitter.emitSignedVarInt(value.getLimitedValue());
427 unsigned numActiveWords = value.getActiveWords();
428 emitter.emitVarInt(numActiveWords);
430 const uint64_t *rawValueData = value.getRawData();
431 for (
unsigned i = 0; i < numActiveWords; ++i)
432 emitter.emitSignedVarInt(rawValueData[i]);
435 void writeAPFloatWithKnownSemantics(
const APFloat &value)
override {
436 writeAPIntWithKnownWidth(value.bitcastToAPInt());
439 void writeOwnedString(StringRef str)
override {
440 emitter.emitVarInt(stringSection.insert(str));
444 emitter.emitVarInt(blob.size());
446 reinterpret_cast<const uint8_t *
>(blob.data()), blob.size()));
449 void writeOwnedBool(
bool value)
override { emitter.emitByte(value); }
451 int64_t getBytecodeVersion()
const override {
return bytecodeVersion; }
454 getDialectVersion(StringRef dialectName)
const override {
455 auto dialectEntry = dialectVersionMap.find(dialectName);
456 if (dialectEntry == dialectVersionMap.end())
458 return dialectEntry->getValue().get();
462 int64_t bytecodeVersion;
463 EncodingEmitter &emitter;
465 StringSectionBuilder &stringSection;
466 const DialectVersionMapT &dialectVersionMap;
470 class PropertiesSectionBuilder {
473 StringSectionBuilder &stringSection,
475 : numberingState(numberingState), stringSection(stringSection),
480 std::optional<ssize_t> emit(
Operation *op) {
481 EncodingEmitter propertiesEmitter;
489 EncodingEmitter sizeEmitter;
490 sizeEmitter.emitVarInt(numberingState.getNumber(prop));
492 llvm::raw_svector_ostream os(scratch);
493 sizeEmitter.writeTo(os);
494 return emit(scratch);
497 EncodingEmitter emitter;
498 DialectWriter propertiesWriter(config.bytecodeVersion, emitter,
499 numberingState, stringSection,
500 config.dialectVersionMap);
501 auto iface = cast<BytecodeOpInterface>(op);
502 iface.writeProperties(propertiesWriter);
504 llvm::raw_svector_ostream os(scratch);
506 return emit(scratch);
510 void write(EncodingEmitter &emitter) {
511 emitter.emitVarInt(propertiesStorage.size());
512 if (propertiesStorage.empty())
514 for (
const auto &storage : propertiesStorage) {
515 if (storage.empty()) {
519 emitter.emitBytes(
ArrayRef(
reinterpret_cast<const uint8_t *
>(&storage[0]),
525 bool empty() {
return propertiesStorage.empty(); }
535 EncodingEmitter sizeEmitter;
536 sizeEmitter.emitVarInt(rawProperties.size());
537 llvm::raw_svector_ostream os(sizeScratch);
538 sizeEmitter.writeTo(os);
541 size_t index = propertiesStorage.size();
542 propertiesStorage.emplace_back();
543 std::vector<char> &newStorage = propertiesStorage.back();
544 size_t propertiesSize = sizeScratch.size() + rawProperties.size();
545 newStorage.reserve(propertiesSize);
546 newStorage.insert(newStorage.end(), sizeScratch.begin(), sizeScratch.end());
547 newStorage.insert(newStorage.end(), rawProperties.begin(),
548 rawProperties.end());
552 auto inserted = propertiesUniquing.insert(
554 if (!inserted.second)
555 propertiesStorage.pop_back();
556 return inserted.first->getSecond();
560 std::vector<std::vector<char>> propertiesStorage;
564 StringSectionBuilder &stringSection;
572 class RawEmitterOstream :
public raw_ostream {
574 explicit RawEmitterOstream(EncodingEmitter &emitter) : emitter(emitter) {
579 void write_impl(
const char *ptr,
size_t size)
override {
580 emitter.emitBytes({
reinterpret_cast<const uint8_t *
>(ptr), size});
582 uint64_t current_pos()
const override {
return emitter.size(); }
585 EncodingEmitter &emitter;
589 void EncodingEmitter::writeTo(raw_ostream &os)
const {
590 for (
auto &prevResult : prevResultList)
591 os.write((
const char *)prevResult.data(), prevResult.size());
592 os.write((
const char *)currentResult.data(), currentResult.size());
595 void EncodingEmitter::emitMultiByteVarInt(uint64_t value) {
599 uint64_t it = value >> 7;
600 for (
size_t numBytes = 2; numBytes < 9; ++numBytes) {
601 if (LLVM_LIKELY(it >>= 7) == 0) {
602 uint64_t encodedValue = (value << 1) | 0x1;
603 encodedValue <<= (numBytes - 1);
604 llvm::support::ulittle64_t encodedValueLE(encodedValue);
605 emitBytes({
reinterpret_cast<uint8_t *
>(&encodedValueLE), numBytes});
613 llvm::support::ulittle64_t valueLE(value);
614 emitBytes({
reinterpret_cast<uint8_t *
>(&valueLE),
sizeof(valueLE)});
622 class BytecodeWriter {
625 : numberingState(op, config), config(config.getImpl()),
626 propertiesSection(numberingState, stringSection, config.getImpl()) {}
635 void writeDialectSection(EncodingEmitter &emitter);
640 void writeAttrTypeSection(EncodingEmitter &emitter);
653 return succeeded(writeRegion(emitter, ®ion));
660 void writeResourceSection(
Operation *op, EncodingEmitter &emitter);
665 void writeStringSection(EncodingEmitter &emitter);
670 void writePropertiesSection(EncodingEmitter &emitter);
675 void writeUseListOrders(EncodingEmitter &emitter, uint8_t &opEncodingMask,
682 StringSectionBuilder stringSection;
691 PropertiesSectionBuilder propertiesSection;
696 EncodingEmitter emitter;
700 emitter.emitString(
"ML\xefR");
706 <<
"unsupported version requested " << config.bytecodeVersion
707 <<
", must be in range ["
710 emitter.emitVarInt(config.bytecodeVersion);
713 emitter.emitNulTerminatedString(config.producer);
716 writeDialectSection(emitter);
719 writeAttrTypeSection(emitter);
722 if (
failed(writeIRSection(emitter, rootOp)))
726 writeResourceSection(rootOp, emitter);
729 writeStringSection(emitter);
733 writePropertiesSection(emitter);
734 else if (!propertiesSection.empty())
736 "unexpected properties emitted incompatible with bytecode <5");
751 template <
typename EntriesT,
typename EntryCallbackT>
753 EntryCallbackT &&callback) {
754 for (
auto it = entries.begin(), e = entries.end(); it != e;) {
755 auto groupStart = it++;
759 it = std::find_if(it, e, [&](
const auto &entry) {
760 return entry.dialect != currentDialect;
764 emitter.emitVarInt(currentDialect->
number);
765 emitter.emitVarInt(std::distance(groupStart, it));
768 for (
auto &entry : llvm::make_range(groupStart, it))
773 void BytecodeWriter::writeDialectSection(EncodingEmitter &emitter) {
774 EncodingEmitter dialectEmitter;
777 auto dialects = numberingState.getDialects();
778 dialectEmitter.emitVarInt(llvm::size(dialects));
781 size_t nameID = stringSection.insert(dialect.name);
784 dialectEmitter.emitVarInt(nameID);
789 EncodingEmitter versionEmitter;
790 if (dialect.interface) {
792 DialectWriter versionWriter(config.bytecodeVersion, versionEmitter,
793 numberingState, stringSection,
794 config.dialectVersionMap);
795 dialect.interface->writeVersion(versionWriter);
801 size_t versionAvailable = versionEmitter.size() > 0;
802 dialectEmitter.emitVarIntWithFlag(nameID, versionAvailable);
803 if (versionAvailable)
805 std::move(versionEmitter));
809 dialectEmitter.emitVarInt(size(numberingState.getOpNames()));
813 size_t stringId = stringSection.insert(name.name.stripDialect());
815 dialectEmitter.emitVarInt(stringId);
817 dialectEmitter.emitVarIntWithFlag(stringId, name.name.isRegistered());
827 void BytecodeWriter::writeAttrTypeSection(EncodingEmitter &emitter) {
828 EncodingEmitter attrTypeEmitter;
829 EncodingEmitter offsetEmitter;
830 offsetEmitter.emitVarInt(llvm::size(numberingState.getAttributes()));
831 offsetEmitter.emitVarInt(llvm::size(numberingState.getTypes()));
834 uint64_t prevOffset = 0;
835 auto emitAttrOrType = [&](
auto &entry) {
836 auto entryValue = entry.getValue();
838 auto emitAttrOrTypeRawImpl = [&]() ->
void {
839 RawEmitterOstream(attrTypeEmitter) << entryValue;
840 attrTypeEmitter.emitByte(0);
842 auto emitAttrOrTypeImpl = [&]() ->
bool {
845 if (entryValue.template hasTrait<TypeTrait::IsMutable>() ||
846 entryValue.template hasTrait<AttributeTrait::IsMutable>()) {
847 emitAttrOrTypeRawImpl();
851 DialectWriter dialectWriter(config.bytecodeVersion, attrTypeEmitter,
852 numberingState, stringSection,
853 config.dialectVersionMap);
854 if constexpr (std::is_same_v<std::decay_t<decltype(entryValue)>,
Type>) {
855 for (
const auto &callback : config.typeWriterCallbacks) {
856 if (
succeeded(callback->write(entryValue, dialectWriter)))
860 entry.dialect->interface) {
861 if (
succeeded(interface->writeType(entryValue, dialectWriter)))
865 for (
const auto &callback : config.attributeWriterCallbacks) {
866 if (
succeeded(callback->write(entryValue, dialectWriter)))
870 entry.dialect->interface) {
871 if (
succeeded(interface->writeAttribute(entryValue, dialectWriter)))
878 emitAttrOrTypeRawImpl();
882 bool hasCustomEncoding = emitAttrOrTypeImpl();
885 uint64_t curOffset = attrTypeEmitter.size();
886 offsetEmitter.emitVarIntWithFlag(curOffset - prevOffset, hasCustomEncoding);
887 prevOffset = curOffset;
898 std::move(offsetEmitter));
905 LogicalResult BytecodeWriter::writeBlock(EncodingEmitter &emitter,
908 bool hasArgs = !args.empty();
913 unsigned numOps = numberingState.getOperationCount(block);
914 emitter.emitVarIntWithFlag(numOps, hasArgs);
918 emitter.emitVarInt(args.size());
922 emitter.emitVarIntWithFlag(numberingState.getNumber(arg.getType()),
923 !isa<UnknownLoc>(argLoc));
924 if (!isa<UnknownLoc>(argLoc))
925 emitter.emitVarInt(numberingState.getNumber(argLoc));
927 emitter.emitVarInt(numberingState.getNumber(arg.getType()));
928 emitter.emitVarInt(numberingState.getNumber(argLoc));
932 uint64_t maskOffset = emitter.size();
933 uint8_t encodingMask = 0;
935 writeUseListOrders(emitter, encodingMask, args);
937 emitter.patchByte(maskOffset, encodingMask);
943 if (
failed(writeOp(emitter, &op)))
949 emitter.emitVarInt(numberingState.getNumber(op->
getName()));
954 uint64_t maskOffset = emitter.size();
955 uint8_t opEncodingMask = 0;
959 emitter.emitVarInt(numberingState.getNumber(op->
getLoc()));
968 if (!attrs.empty()) {
970 emitter.emitVarInt(numberingState.getNumber(attrs));
976 std::optional<ssize_t> propertiesId = propertiesSection.emit(op);
977 if (propertiesId.has_value()) {
979 emitter.emitVarInt(*propertiesId);
986 emitter.emitVarInt(numResults);
988 emitter.emitVarInt(numberingState.getNumber(type));
994 emitter.emitVarInt(numOperands);
996 emitter.emitVarInt(numberingState.getNumber(operand));
1002 emitter.emitVarInt(numSuccessors);
1004 emitter.emitVarInt(numberingState.getNumber(successor));
1018 emitter.patchByte(maskOffset, opEncodingMask);
1025 bool isIsolatedFromAbove = numberingState.isIsolatedFromAbove(op);
1026 emitter.emitVarIntWithFlag(numRegions, isIsolatedFromAbove);
1030 if (isIsolatedFromAbove &&
1032 EncodingEmitter regionEmitter;
1044 void BytecodeWriter::writeUseListOrders(EncodingEmitter &emitter,
1045 uint8_t &opEncodingMask,
1050 auto value = item.value();
1053 if (value.use_empty() || value.hasOneUse())
1059 bool alreadyOrdered =
true;
1060 auto &firstUse = *value.use_begin();
1062 firstUse, numberingState.getNumber(firstUse.getOwner()));
1068 use.value(), numberingState.getNumber(use.value().getOwner()));
1072 alreadyOrdered &= (prevID > currentID);
1073 useListPairs.push_back({use.index(), currentID});
1083 useListPairs.begin(), useListPairs.end(),
1084 [](
auto elem1,
auto elem2) { return elem1.second > elem2.second; });
1086 map.try_emplace(item.index(), llvm::map_range(useListPairs, [](
auto elem) {
1097 if (range.size() != 1)
1098 emitter.emitVarInt(map.size());
1100 for (
const auto &item : map) {
1101 auto resultIdx = item.getFirst();
1102 auto useListOrder = item.getSecond();
1107 size_t shuffledElements =
1109 [](
auto item) {
return item.index() != item.value(); });
1110 bool indexPairEncoding = shuffledElements < (useListOrder.size() / 2);
1113 if (range.size() != 1)
1114 emitter.emitVarInt(resultIdx);
1116 if (indexPairEncoding) {
1117 emitter.emitVarIntWithFlag(shuffledElements * 2, indexPairEncoding);
1119 if (pair.index() != pair.value()) {
1120 emitter.emitVarInt(pair.value());
1121 emitter.emitVarInt(pair.index());
1125 emitter.emitVarIntWithFlag(useListOrder.size(), indexPairEncoding);
1126 for (
const auto &index : useListOrder)
1127 emitter.emitVarInt(index);
1132 LogicalResult BytecodeWriter::writeRegion(EncodingEmitter &emitter,
1136 if (region->
empty()) {
1137 emitter.emitVarInt( 0);
1142 unsigned numBlocks, numValues;
1143 std::tie(numBlocks, numValues) = numberingState.getBlockValueCount(region);
1144 emitter.emitVarInt(numBlocks);
1145 emitter.emitVarInt(numValues);
1148 for (
Block &block : *region)
1149 if (
failed(writeBlock(emitter, &block)))
1154 LogicalResult BytecodeWriter::writeIRSection(EncodingEmitter &emitter,
1156 EncodingEmitter irEmitter;
1161 irEmitter.emitVarIntWithFlag( 1,
false);
1164 if (
failed(writeOp(irEmitter, op)))
1181 ResourceBuilder(EncodingEmitter &emitter, StringSectionBuilder &stringSection,
1182 PostProcessFn postProcessFn,
bool shouldElideData)
1183 : emitter(emitter), stringSection(stringSection),
1184 postProcessFn(postProcessFn), shouldElideData(shouldElideData) {}
1185 ~ResourceBuilder()
override =
default;
1188 uint32_t dataAlignment)
final {
1189 if (!shouldElideData)
1190 emitter.emitOwnedBlobAndAlignment(data, dataAlignment);
1193 void buildBool(StringRef key,
bool data)
final {
1194 if (!shouldElideData)
1195 emitter.emitByte(data);
1198 void buildString(StringRef key, StringRef data)
final {
1199 if (!shouldElideData)
1200 emitter.emitVarInt(stringSection.insert(data));
1205 EncodingEmitter &emitter;
1206 StringSectionBuilder &stringSection;
1207 PostProcessFn postProcessFn;
1208 bool shouldElideData =
false;
1212 void BytecodeWriter::writeResourceSection(
Operation *op,
1213 EncodingEmitter &emitter) {
1214 EncodingEmitter resourceEmitter;
1215 EncodingEmitter resourceOffsetEmitter;
1216 uint64_t prevOffset = 0;
1223 uint64_t curOffset = resourceEmitter.size();
1224 curResourceEntries.emplace_back(key, kind, curOffset - prevOffset);
1225 prevOffset = curOffset;
1229 auto emitResourceGroup = [&](uint64_t key) {
1230 resourceOffsetEmitter.emitVarInt(key);
1231 resourceOffsetEmitter.emitVarInt(curResourceEntries.size());
1232 for (
auto [key, kind, size] : curResourceEntries) {
1233 resourceOffsetEmitter.emitVarInt(stringSection.insert(key));
1234 resourceOffsetEmitter.emitVarInt(size);
1235 resourceOffsetEmitter.emitByte(kind);
1240 ResourceBuilder entryBuilder(resourceEmitter, stringSection,
1241 appendResourceOffset,
1242 config.shouldElideResourceData);
1245 resourceOffsetEmitter.emitVarInt(config.externalResourcePrinters.size());
1246 for (
const auto &printer : config.externalResourcePrinters) {
1247 curResourceEntries.clear();
1248 printer->buildResources(op, entryBuilder);
1249 emitResourceGroup(stringSection.insert(printer->getName()));
1254 if (!dialect.asmInterface)
1256 curResourceEntries.clear();
1257 dialect.asmInterface->buildResources(op, dialect.resources, entryBuilder);
1262 for (
const auto &resource : dialect.resourceMap)
1263 if (resource.second->isDeclaration)
1267 if (!curResourceEntries.empty())
1268 emitResourceGroup(dialect.number);
1272 if (resourceOffsetEmitter.size() == 0)
1276 std::move(resourceOffsetEmitter));
1283 void BytecodeWriter::writeStringSection(EncodingEmitter &emitter) {
1284 EncodingEmitter stringEmitter;
1285 stringSection.write(stringEmitter);
1292 void BytecodeWriter::writePropertiesSection(EncodingEmitter &emitter) {
1293 EncodingEmitter propertiesEmitter;
1294 propertiesSection.write(propertiesEmitter);
1296 std::move(propertiesEmitter));
1305 BytecodeWriter writer(op, config);
1306 return writer.write(op, os);
static void writeDialectGrouping(EncodingEmitter &emitter, EntriesT &&entries, EntryCallbackT &&callback)
Write the given entries in contiguous groups with the same parent dialect.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
This class represents an opaque handle to a dialect resource entry.
This class is used to build resource entries for use by the printer.
A class to interact with the attributes and types printer when emitting MLIR bytecode.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgListType getArguments()
This class contains the configuration used for the bytecode writer.
void attachTypeCallback(std::unique_ptr< AttrTypeBytecodeWriter< Type >> callback)
llvm::StringMap< std::unique_ptr< DialectVersion > > & getDialectVersionMap() const
A map containing the dialect versions to emit.
void setElideResourceDataFlag(bool shouldElideResourceData=true)
Set a boolean flag to skip emission of resources into the bytecode file.
BytecodeWriterConfig(StringRef producer="MLIR" LLVM_VERSION_STRING)
producer is an optional string that can be used to identify the producer of the bytecode when reading...
void attachFallbackResourcePrinter(FallbackAsmResourceMap &map)
Attach resource printers to the AsmState for the fallback resources in the given map.
int64_t getDesiredBytecodeVersion() const
Get the set desired bytecode version to emit.
void setDialectVersion(std::unique_ptr< DialectVersion > dialectVersion) const
Set a given dialect version to emit on the map.
ArrayRef< std::unique_ptr< AttrTypeBytecodeWriter< Type > > > getTypeWriterCallbacks() const
ArrayRef< std::unique_ptr< AttrTypeBytecodeWriter< Attribute > > > getAttributeWriterCallbacks() const
Retrieve the callbacks.
void setDesiredBytecodeVersion(int64_t bytecodeVersion)
Set the desired bytecode version to emit.
void attachResourcePrinter(std::unique_ptr< AsmResourcePrinter > printer)
Attach the given resource printer to the writer configuration.
void attachAttributeCallback(std::unique_ptr< AttrTypeBytecodeWriter< Attribute >> callback)
Attach a custom bytecode printer callback to the configuration for the emission of custom type/attrib...
This class defines a virtual interface for writing to a bytecode stream, providing hooks into the byt...
This class provides support for representing a failure result, or a valid value of type T.
A fallback map containing external resources not explicitly handled by another parser/printer.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Operation is the basic unit of execution within MLIR.
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
unsigned getNumSuccessors()
bool isRegistered()
Returns true if this operation has a registered operation description, otherwise false.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
unsigned getNumOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
SuccessorRange getSuccessors()
result_range getResults()
int getPropertiesStorageSize() const
Returns the properties storage size.
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
This class manages numbering IR entities in preparation of bytecode emission.
@ kAttrType
This section contains the attributes and types referenced within an IR module.
@ kAttrTypeOffset
This section contains the offsets for the attribute and types within the AttrType section.
@ kIR
This section contains the list of operations serialized into the bytecode, and their nested regions/o...
@ kResource
This section contains the resources of the bytecode.
@ kResourceOffset
This section contains the offsets of resources within the Resource section.
@ kDialect
This section contains the dialects referenced within an IR module.
@ kString
This section contains strings referenced within the bytecode.
@ kDialectVersions
This section contains the versions of each dialect.
@ kProperties
This section contains the properties for the operations.
static uint64_t getUseID(OperandT &val, unsigned ownerID)
Get the unique ID of a value use.
@ kUseListOrdering
Use-list ordering started to be encoded in version 3.
@ kAlignmentByte
An arbitrary value used to fill alignment padding.
@ kVersion
The current bytecode version.
@ kLazyLoading
Support for lazy-loading of isolated region was added in version 2.
@ kDialectVersioning
Dialects versioning was added in version 1.
@ kElideUnknownBlockArgLocation
Avoid recording unknown locations on block arguments (compression) started in version 4.
@ kNativePropertiesEncoding
Support for encoding properties natively in bytecode instead of merged with the discardable attribute...
@ kMinSupportedVersion
The minimum supported version of the bytecode.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult writeBytecodeToFile(Operation *op, raw_ostream &os, const BytecodeWriterConfig &config={})
Write the bytecode for the given operation to the provided output stream.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
StringRef producer
The producer of the bytecode.
llvm::StringMap< std::unique_ptr< DialectVersion > > dialectVersionMap
A map containing dialect version information for each dialect to emit.
llvm::SmallVector< std::unique_ptr< AttrTypeBytecodeWriter< Attribute > > > attributeWriterCallbacks
Printer callbacks used to emit custom type and attribute encodings.
SmallVector< std::unique_ptr< AsmResourcePrinter > > externalResourcePrinters
A collection of non-dialect resource printers.
llvm::SmallVector< std::unique_ptr< AttrTypeBytecodeWriter< Type > > > typeWriterCallbacks
This class represents an efficient way to signal success or failure.
This class represents a numbering entry for an Dialect.
unsigned number
The number assigned to the dialect.