62 auto sortByDialect = [](
unsigned dialectToOrderFirst,
const auto &lhs,
64 if (lhs->dialect->number == dialectToOrderFirst)
65 return rhs->dialect->number != dialectToOrderFirst;
66 if (rhs->dialect->number == dialectToOrderFirst)
68 return lhs->dialect->number < rhs->dialect->number;
71 unsigned dialectToOrderFirst = 0;
72 size_t elementsInByteGroup = 0;
73 auto iterRange = range;
74 for (
unsigned i = 1; i < 9; ++i) {
78 elementsInByteGroup = (1ULL << (7ULL * i)) - elementsInByteGroup;
82 auto byteSubRange = iterRange.take_front(elementsInByteGroup);
83 iterRange = iterRange.drop_front(byteSubRange.size());
86 llvm::stable_sort(byteSubRange, [&](
const auto &lhs,
const auto &rhs) {
87 return sortByDialect(dialectToOrderFirst, lhs, rhs);
93 dialectToOrderFirst = byteSubRange.back()->dialect->number;
96 if (iterRange.empty())
112 numberContext.emplace_back(®ion, nextValueID);
115 while (!numberContext.empty()) {
117 std::tie(region, nextValueID) = numberContext.pop_back_val();
124 unsigned opFirstValueID =
127 numberContext.emplace_back(®ion, opFirstValueID);
136 dialect.second->number = idx;
143 auto sortByRefCountFn = [](
const auto &lhs,
const auto &rhs) {
144 return lhs->refCount > rhs->refCount;
146 llvm::stable_sort(orderedAttrs, sortByRefCountFn);
147 llvm::stable_sort(orderedOpNames, sortByRefCountFn);
148 llvm::stable_sort(orderedTypes, sortByRefCountFn);
160 finalizeDialectResourceNumberings(op);
163 void IRNumberingState::number(
Attribute attr) {
164 auto it = attrs.insert({attr,
nullptr});
166 ++it.first->second->refCount;
170 it.first->second = numbering;
171 orderedAttrs.push_back(numbering);
177 if (OpaqueAttr opaqueAttr = attr.
dyn_cast<OpaqueAttr>()) {
178 numbering->dialect = &numberDialect(opaqueAttr.getDialectNamespace());
181 numbering->dialect = &numberDialect(&attr.
getDialect());
185 if (
const auto *interface = numbering->dialect->interface) {
188 NumberingDialectWriter writer(*
this);
189 if (
succeeded(interface->writeAttribute(attr, writer)))
198 llvm::raw_null_ostream dummyOS;
199 attr.
print(dummyOS, tempState);
202 for (
const auto &it : tempState.getDialectResources())
203 number(it.getFirst(), it.getSecond().getArrayRef());
206 void IRNumberingState::number(
Block &block) {
209 valueIDs.try_emplace(arg, nextValueID++);
210 number(arg.getLoc());
211 number(arg.getType());
215 unsigned &numOps = blockOperationCounts[&block];
225 numbering = &numberDialect(dialect->getNamespace());
226 numbering->
interface = dyn_cast<BytecodeDialectInterface>(dialect);
227 numbering->
asmInterface = dyn_cast<OpAsmDialectInterface>(dialect);
232 auto IRNumberingState::numberDialect(StringRef dialect) ->
DialectNumbering & {
235 numbering =
new (dialectAllocator.Allocate())
241 void IRNumberingState::number(
Region ®ion) {
244 size_t firstValueID = nextValueID;
247 size_t blockCount = 0;
249 blockIDs.try_emplace(&it.value(), it.index());
255 regionBlockValueCounts.try_emplace(®ion, blockCount,
256 nextValueID - firstValueID);
259 void IRNumberingState::number(
Operation &op) {
264 valueIDs.try_emplace(result, nextValueID++);
265 number(result.getType());
270 if (!dictAttr.empty())
284 dialectNumber = &numberDialect(dialect);
289 new (opNameAllocator.Allocate())
OpNameNumbering(dialectNumber, opName);
290 orderedOpNames.push_back(numbering);
293 void IRNumberingState::number(
Type type) {
294 auto it = types.insert({type,
nullptr});
296 ++it.first->second->refCount;
299 auto *numbering =
new (typeAllocator.Allocate())
TypeNumbering(type);
300 it.first->second = numbering;
301 orderedTypes.push_back(numbering);
307 if (OpaqueType opaqueType = type.
dyn_cast<OpaqueType>()) {
308 numbering->
dialect = &numberDialect(opaqueType.getDialectNamespace());
318 NumberingDialectWriter writer(*
this);
319 if (
succeeded(interface->writeType(type, writer)))
328 llvm::raw_null_ostream dummyOS;
329 type.
print(dummyOS, tempState);
332 for (
const auto &it : tempState.getDialectResources())
333 number(it.getFirst(), it.getSecond().getArrayRef());
336 void IRNumberingState::number(
Dialect *dialect,
341 "expected dialect owning a resource to implement OpAsmDialectInterface");
343 for (
const auto &resource : resources) {
345 if (!dialectNumber.
resources.insert(resource))
351 dialectNumber.
resourceMap.insert({numbering->key, numbering});
352 dialectResources.try_emplace(resource, numbering);
359 NumberingResourceBuilder(
DialectNumbering *dialect,
unsigned &nextResourceID)
360 : dialect(dialect), nextResourceID(nextResourceID) {}
361 ~NumberingResourceBuilder()
override =
default;
366 void buildBool(StringRef key,
bool)
final { numberEntry(key); }
367 void buildString(StringRef key, StringRef)
final {
373 void numberEntry(StringRef key) {
376 auto it = dialect->resourceMap.find(key);
377 if (it != dialect->resourceMap.end()) {
378 it->second->number = nextResourceID++;
379 it->second->isDeclaration =
false;
384 unsigned &nextResourceID;
388 void IRNumberingState::finalizeDialectResourceNumberings(
Operation *rootOp) {
389 unsigned nextResourceID = 0;
391 if (!dialect.asmInterface)
393 NumberingResourceBuilder entryBuilder(&dialect, nextResourceID);
394 dialect.asmInterface->buildResources(rootOp, dialect.resources,
401 for (
const auto &it : dialect.resourceMap)
402 if (it.second->isDeclaration)
403 it.second->number = nextResourceID++;
static void groupByDialectPerByte(T range)
Group and sort the elements of the given range by their parent dialect.
This class represents an opaque handle to a dialect resource entry.
Dialect * getDialect() const
Return the dialect that owns the resource.
This class is used to build resource entries for use by the printer.
This class provides management for the lifetime of the state used when printing the IR.
Attributes are known-constant values of operations.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
void print(raw_ostream &os, bool elideType=false) const
Print the attribute.
MLIRContext * getContext() const
Return the context this attribute belongs to.
bool hasTrait()
Returns true if the type was registered with a particular trait.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
BlockArgListType getArguments()
This class defines a virtual interface for writing to a bytecode stream, providing hooks into the byt...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
This is a value defined by a result of an operation.
This class provides the API for ops that are known to be isolated from above.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
StringRef getDialectNamespace() const
Return the name of the dialect this operation is registered to.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Location getLoc()
The source location the operation was defined or derived from.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
OperationName getName()
The name of an operation is the key identifier for it.
result_range getResults()
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
void print(raw_ostream &os) const
Print the current type.
Dialect & getDialect() const
Get the dialect this type is registered to.
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool hasTrait()
Returns true if the type was registered with a particular trait.
This class manages numbering IR entities in preparation of bytecode emission.
auto getDialects()
Return the numbered dialects.
IRNumberingState(Operation *op)
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
This header declares functions that assit transformations in the MemRef dialect.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
void writeType(Type type) override
Write a reference to the given type.
NumberingDialectWriter(IRNumberingState &state)
void writeVarInt(uint64_t) override
Stubbed out methods that are not used for numbering.
void writeOwnedString(StringRef) override
Write a string to the bytecode, which is owned by the caller and is guaranteed to not die before the ...
IRNumberingState & state
The parent numbering state that is populated by this writer.
void writeAttribute(Attribute attr) override
Write a reference to the given attribute.
void writeResourceHandle(const AsmDialectResourceHandle &resource) override
Write the given handle to a dialect resource.
void writeAPIntWithKnownWidth(const APInt &value) override
Write an APInt to the bytecode stream whose bitwidth will be known externally at read time.
void writeSignedVarInt(int64_t value) override
Write a signed variable width integer to the output stream.
void writeOwnedBlob(ArrayRef< char > blob) override
Write a blob to the bytecode, which is owned by the caller and is guaranteed to not die before the en...
void writeAPFloatWithKnownSemantics(const APFloat &value) override
Write an APFloat to the bytecode stream whose semantics will be known externally at read time.
This class represents a numbering entry for an Dialect.
const BytecodeDialectInterface * interface
The bytecode dialect interface of the dialect if defined.
llvm::MapVector< StringRef, DialectResourceNumbering * > resourceMap
A mapping from resource key to the corresponding resource numbering entry.
SetVector< AsmDialectResourceHandle > resources
The referenced resources of this dialect.
const OpAsmDialectInterface * asmInterface
The asm dialect interface of the dialect if defined.
This class represents a numbering entry for a dialect resource.
This trait is used to determine if a storage user, like Type, is mutable or not.