xref: /llvm-project/mlir/lib/AsmParser/AsmParserState.cpp (revision 59b7461c139d30ea57db4211decebe43117676fa)
1c60b897dSRiver Riddle //===- AsmParserState.cpp -------------------------------------------------===//
2c60b897dSRiver Riddle //
3c60b897dSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c60b897dSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5c60b897dSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c60b897dSRiver Riddle //
7c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
8c60b897dSRiver Riddle 
9c60b897dSRiver Riddle #include "mlir/AsmParser/AsmParserState.h"
10285a229fSMehdi Amini #include "mlir/IR/Attributes.h"
11c60b897dSRiver Riddle #include "mlir/IR/Operation.h"
12c60b897dSRiver Riddle #include "mlir/IR/SymbolTable.h"
13285a229fSMehdi Amini #include "mlir/IR/Types.h"
14285a229fSMehdi Amini #include "mlir/IR/Value.h"
15285a229fSMehdi Amini #include "mlir/Support/LLVM.h"
16285a229fSMehdi Amini #include "llvm/ADT/ArrayRef.h"
17285a229fSMehdi Amini #include "llvm/ADT/STLExtras.h"
18c60b897dSRiver Riddle #include "llvm/ADT/StringExtras.h"
19285a229fSMehdi Amini #include "llvm/ADT/StringMap.h"
20285a229fSMehdi Amini #include "llvm/ADT/iterator.h"
21285a229fSMehdi Amini #include "llvm/Support/ErrorHandling.h"
22285a229fSMehdi Amini #include <cassert>
23285a229fSMehdi Amini #include <cctype>
24285a229fSMehdi Amini #include <memory>
25285a229fSMehdi Amini #include <utility>
26c60b897dSRiver Riddle 
27c60b897dSRiver Riddle using namespace mlir;
28c60b897dSRiver Riddle 
29c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
30c60b897dSRiver Riddle // AsmParserState::Impl
31c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
32c60b897dSRiver Riddle 
33c60b897dSRiver Riddle struct AsmParserState::Impl {
34c60b897dSRiver Riddle   /// A map from a SymbolRefAttr to a range of uses.
35c60b897dSRiver Riddle   using SymbolUseMap =
36c60b897dSRiver Riddle       DenseMap<Attribute, SmallVector<SmallVector<SMRange>, 0>>;
37c60b897dSRiver Riddle 
38c60b897dSRiver Riddle   struct PartialOpDef {
39c60b897dSRiver Riddle     explicit PartialOpDef(const OperationName &opName) {
40c60b897dSRiver Riddle       if (opName.hasTrait<OpTrait::SymbolTable>())
41c60b897dSRiver Riddle         symbolTable = std::make_unique<SymbolUseMap>();
42c60b897dSRiver Riddle     }
43c60b897dSRiver Riddle 
44c60b897dSRiver Riddle     /// Return if this operation is a symbol table.
45c60b897dSRiver Riddle     bool isSymbolTable() const { return symbolTable.get(); }
46c60b897dSRiver Riddle 
47c60b897dSRiver Riddle     /// If this operation is a symbol table, the following contains symbol uses
48c60b897dSRiver Riddle     /// within this operation.
49c60b897dSRiver Riddle     std::unique_ptr<SymbolUseMap> symbolTable;
50c60b897dSRiver Riddle   };
51c60b897dSRiver Riddle 
52c60b897dSRiver Riddle   /// Resolve any symbol table uses in the IR.
53c60b897dSRiver Riddle   void resolveSymbolUses();
54c60b897dSRiver Riddle 
55c60b897dSRiver Riddle   /// A mapping from operations in the input source file to their parser state.
56c60b897dSRiver Riddle   SmallVector<std::unique_ptr<OperationDefinition>> operations;
57c60b897dSRiver Riddle   DenseMap<Operation *, unsigned> operationToIdx;
58c60b897dSRiver Riddle 
59c60b897dSRiver Riddle   /// A mapping from blocks in the input source file to their parser state.
60c60b897dSRiver Riddle   SmallVector<std::unique_ptr<BlockDefinition>> blocks;
61c60b897dSRiver Riddle   DenseMap<Block *, unsigned> blocksToIdx;
62c60b897dSRiver Riddle 
63a5b584d8SMogball   /// A mapping from aliases in the input source file to their parser state.
64a5b584d8SMogball   SmallVector<std::unique_ptr<AttributeAliasDefinition>> attrAliases;
65a5b584d8SMogball   SmallVector<std::unique_ptr<TypeAliasDefinition>> typeAliases;
66a5b584d8SMogball   llvm::StringMap<unsigned> attrAliasToIdx;
67a5b584d8SMogball   llvm::StringMap<unsigned> typeAliasToIdx;
68a5b584d8SMogball 
69c60b897dSRiver Riddle   /// A set of value definitions that are placeholders for forward references.
70c60b897dSRiver Riddle   /// This map should be empty if the parser finishes successfully.
71c60b897dSRiver Riddle   DenseMap<Value, SmallVector<SMLoc>> placeholderValueUses;
72c60b897dSRiver Riddle 
73c60b897dSRiver Riddle   /// The symbol table operations within the IR.
74c60b897dSRiver Riddle   SmallVector<std::pair<Operation *, std::unique_ptr<SymbolUseMap>>>
75c60b897dSRiver Riddle       symbolTableOperations;
76c60b897dSRiver Riddle 
77c60b897dSRiver Riddle   /// A stack of partial operation definitions that have been started but not
78c60b897dSRiver Riddle   /// yet finalized.
79c60b897dSRiver Riddle   SmallVector<PartialOpDef> partialOperations;
80c60b897dSRiver Riddle 
81c60b897dSRiver Riddle   /// A stack of symbol use scopes. This is used when collecting symbol table
82c60b897dSRiver Riddle   /// uses during parsing.
83c60b897dSRiver Riddle   SmallVector<SymbolUseMap *> symbolUseScopes;
84c60b897dSRiver Riddle 
85c60b897dSRiver Riddle   /// A symbol table containing all of the symbol table operations in the IR.
86c60b897dSRiver Riddle   SymbolTableCollection symbolTable;
87c60b897dSRiver Riddle };
88c60b897dSRiver Riddle 
89c60b897dSRiver Riddle void AsmParserState::Impl::resolveSymbolUses() {
90c60b897dSRiver Riddle   SmallVector<Operation *> symbolOps;
91c60b897dSRiver Riddle   for (auto &opAndUseMapIt : symbolTableOperations) {
92c60b897dSRiver Riddle     for (auto &it : *opAndUseMapIt.second) {
93c60b897dSRiver Riddle       symbolOps.clear();
94c60b897dSRiver Riddle       if (failed(symbolTable.lookupSymbolIn(
955550c821STres Popp               opAndUseMapIt.first, cast<SymbolRefAttr>(it.first), symbolOps)))
96c60b897dSRiver Riddle         continue;
97c60b897dSRiver Riddle 
98c60b897dSRiver Riddle       for (ArrayRef<SMRange> useRange : it.second) {
99c60b897dSRiver Riddle         for (const auto &symIt : llvm::zip(symbolOps, useRange)) {
100c60b897dSRiver Riddle           auto opIt = operationToIdx.find(std::get<0>(symIt));
101c60b897dSRiver Riddle           if (opIt != operationToIdx.end())
102c60b897dSRiver Riddle             operations[opIt->second]->symbolUses.push_back(std::get<1>(symIt));
103c60b897dSRiver Riddle         }
104c60b897dSRiver Riddle       }
105c60b897dSRiver Riddle     }
106c60b897dSRiver Riddle   }
107c60b897dSRiver Riddle }
108c60b897dSRiver Riddle 
109c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
110c60b897dSRiver Riddle // AsmParserState
111c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
112c60b897dSRiver Riddle 
113c60b897dSRiver Riddle AsmParserState::AsmParserState() : impl(std::make_unique<Impl>()) {}
114c60b897dSRiver Riddle AsmParserState::~AsmParserState() = default;
115c60b897dSRiver Riddle AsmParserState &AsmParserState::operator=(AsmParserState &&other) {
116c60b897dSRiver Riddle   impl = std::move(other.impl);
117c60b897dSRiver Riddle   return *this;
118c60b897dSRiver Riddle }
119c60b897dSRiver Riddle 
120c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
121c60b897dSRiver Riddle // Access State
122c60b897dSRiver Riddle 
123c60b897dSRiver Riddle auto AsmParserState::getBlockDefs() const -> iterator_range<BlockDefIterator> {
124984b800aSserge-sans-paille   return llvm::make_pointee_range(llvm::ArrayRef(impl->blocks));
125c60b897dSRiver Riddle }
126c60b897dSRiver Riddle 
127c60b897dSRiver Riddle auto AsmParserState::getBlockDef(Block *block) const
128c60b897dSRiver Riddle     -> const BlockDefinition * {
129c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(block);
130c60b897dSRiver Riddle   return it == impl->blocksToIdx.end() ? nullptr : &*impl->blocks[it->second];
131c60b897dSRiver Riddle }
132c60b897dSRiver Riddle 
133c60b897dSRiver Riddle auto AsmParserState::getOpDefs() const -> iterator_range<OperationDefIterator> {
134984b800aSserge-sans-paille   return llvm::make_pointee_range(llvm::ArrayRef(impl->operations));
135c60b897dSRiver Riddle }
136c60b897dSRiver Riddle 
137c60b897dSRiver Riddle auto AsmParserState::getOpDef(Operation *op) const
138c60b897dSRiver Riddle     -> const OperationDefinition * {
139c60b897dSRiver Riddle   auto it = impl->operationToIdx.find(op);
140c60b897dSRiver Riddle   return it == impl->operationToIdx.end() ? nullptr
141c60b897dSRiver Riddle                                           : &*impl->operations[it->second];
142c60b897dSRiver Riddle }
143c60b897dSRiver Riddle 
1443bcc63e3SMogball auto AsmParserState::getAttributeAliasDefs() const
1453bcc63e3SMogball     -> iterator_range<AttributeDefIterator> {
1463bcc63e3SMogball   return llvm::make_pointee_range(ArrayRef(impl->attrAliases));
1473bcc63e3SMogball }
1483bcc63e3SMogball 
1493bcc63e3SMogball auto AsmParserState::getAttributeAliasDef(StringRef name) const
1503bcc63e3SMogball     -> const AttributeAliasDefinition * {
1513bcc63e3SMogball   auto it = impl->attrAliasToIdx.find(name);
1523bcc63e3SMogball   return it == impl->attrAliasToIdx.end() ? nullptr
1533bcc63e3SMogball                                           : &*impl->attrAliases[it->second];
1543bcc63e3SMogball }
1553bcc63e3SMogball 
1563bcc63e3SMogball auto AsmParserState::getTypeAliasDefs() const
1573bcc63e3SMogball     -> iterator_range<TypeDefIterator> {
1583bcc63e3SMogball   return llvm::make_pointee_range(ArrayRef(impl->typeAliases));
1593bcc63e3SMogball }
1603bcc63e3SMogball 
1613bcc63e3SMogball auto AsmParserState::getTypeAliasDef(StringRef name) const
1623bcc63e3SMogball     -> const TypeAliasDefinition * {
1633bcc63e3SMogball   auto it = impl->typeAliasToIdx.find(name);
1643bcc63e3SMogball   return it == impl->typeAliasToIdx.end() ? nullptr
1653bcc63e3SMogball                                           : &*impl->typeAliases[it->second];
1663bcc63e3SMogball }
1673bcc63e3SMogball 
168c60b897dSRiver Riddle /// Lex a string token whose contents start at the given `curPtr`. Returns the
169c60b897dSRiver Riddle /// position at the end of the string, after a terminal or invalid character
170c60b897dSRiver Riddle /// (e.g. `"` or `\0`).
171c60b897dSRiver Riddle static const char *lexLocStringTok(const char *curPtr) {
172c60b897dSRiver Riddle   while (char c = *curPtr++) {
173c60b897dSRiver Riddle     // Check for various terminal characters.
174c60b897dSRiver Riddle     if (StringRef("\"\n\v\f").contains(c))
175c60b897dSRiver Riddle       return curPtr;
176c60b897dSRiver Riddle 
177c60b897dSRiver Riddle     // Check for escape sequences.
178c60b897dSRiver Riddle     if (c == '\\') {
179c60b897dSRiver Riddle       // Check a few known escapes and \xx hex digits.
180c60b897dSRiver Riddle       if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')
181c60b897dSRiver Riddle         ++curPtr;
182c60b897dSRiver Riddle       else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))
183c60b897dSRiver Riddle         curPtr += 2;
184c60b897dSRiver Riddle       else
185c60b897dSRiver Riddle         return curPtr;
186c60b897dSRiver Riddle     }
187c60b897dSRiver Riddle   }
188c60b897dSRiver Riddle 
189c60b897dSRiver Riddle   // If we hit this point, we've reached the end of the buffer. Update the end
190c60b897dSRiver Riddle   // pointer to not point past the buffer.
191c60b897dSRiver Riddle   return curPtr - 1;
192c60b897dSRiver Riddle }
193c60b897dSRiver Riddle 
194c60b897dSRiver Riddle SMRange AsmParserState::convertIdLocToRange(SMLoc loc) {
195c60b897dSRiver Riddle   if (!loc.isValid())
196c60b897dSRiver Riddle     return SMRange();
197c60b897dSRiver Riddle   const char *curPtr = loc.getPointer();
198c60b897dSRiver Riddle 
199c60b897dSRiver Riddle   // Check if this is a string token.
200c60b897dSRiver Riddle   if (*curPtr == '"') {
201c60b897dSRiver Riddle     curPtr = lexLocStringTok(curPtr + 1);
202c60b897dSRiver Riddle 
203c60b897dSRiver Riddle     // Otherwise, default to handling an identifier.
204c60b897dSRiver Riddle   } else {
205c60b897dSRiver Riddle     // Return if the given character is a valid identifier character.
206c60b897dSRiver Riddle     auto isIdentifierChar = [](char c) {
207c60b897dSRiver Riddle       return isalnum(c) || c == '$' || c == '.' || c == '_' || c == '-';
208c60b897dSRiver Riddle     };
209c60b897dSRiver Riddle 
210c60b897dSRiver Riddle     while (*curPtr && isIdentifierChar(*(++curPtr)))
211c60b897dSRiver Riddle       continue;
212c60b897dSRiver Riddle   }
213c60b897dSRiver Riddle 
214c60b897dSRiver Riddle   return SMRange(loc, SMLoc::getFromPointer(curPtr));
215c60b897dSRiver Riddle }
216c60b897dSRiver Riddle 
217c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
218c60b897dSRiver Riddle // Populate State
219c60b897dSRiver Riddle 
220c60b897dSRiver Riddle void AsmParserState::initialize(Operation *topLevelOp) {
221c60b897dSRiver Riddle   startOperationDefinition(topLevelOp->getName());
222c60b897dSRiver Riddle 
223c60b897dSRiver Riddle   // If the top-level operation is a symbol table, push a new symbol scope.
224c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
225c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
226c60b897dSRiver Riddle     impl->symbolUseScopes.push_back(partialOpDef.symbolTable.get());
227c60b897dSRiver Riddle }
228c60b897dSRiver Riddle 
229c60b897dSRiver Riddle void AsmParserState::finalize(Operation *topLevelOp) {
230c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
231c60b897dSRiver Riddle          "expected valid partial operation definition");
232c60b897dSRiver Riddle   Impl::PartialOpDef partialOpDef = impl->partialOperations.pop_back_val();
233c60b897dSRiver Riddle 
234c60b897dSRiver Riddle   // If this operation is a symbol table, resolve any symbol uses.
235c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable()) {
236c60b897dSRiver Riddle     impl->symbolTableOperations.emplace_back(
237c60b897dSRiver Riddle         topLevelOp, std::move(partialOpDef.symbolTable));
238c60b897dSRiver Riddle   }
239c60b897dSRiver Riddle   impl->resolveSymbolUses();
240c60b897dSRiver Riddle }
241c60b897dSRiver Riddle 
242c60b897dSRiver Riddle void AsmParserState::startOperationDefinition(const OperationName &opName) {
243c60b897dSRiver Riddle   impl->partialOperations.emplace_back(opName);
244c60b897dSRiver Riddle }
245c60b897dSRiver Riddle 
246c60b897dSRiver Riddle void AsmParserState::finalizeOperationDefinition(
247c60b897dSRiver Riddle     Operation *op, SMRange nameLoc, SMLoc endLoc,
248c60b897dSRiver Riddle     ArrayRef<std::pair<unsigned, SMLoc>> resultGroups) {
249c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
250c60b897dSRiver Riddle          "expected valid partial operation definition");
251c60b897dSRiver Riddle   Impl::PartialOpDef partialOpDef = impl->partialOperations.pop_back_val();
252c60b897dSRiver Riddle 
253c60b897dSRiver Riddle   // Build the full operation definition.
254c60b897dSRiver Riddle   std::unique_ptr<OperationDefinition> def =
255c60b897dSRiver Riddle       std::make_unique<OperationDefinition>(op, nameLoc, endLoc);
256c60b897dSRiver Riddle   for (auto &resultGroup : resultGroups)
257c60b897dSRiver Riddle     def->resultGroups.emplace_back(resultGroup.first,
258c60b897dSRiver Riddle                                    convertIdLocToRange(resultGroup.second));
259c60b897dSRiver Riddle   impl->operationToIdx.try_emplace(op, impl->operations.size());
260c60b897dSRiver Riddle   impl->operations.emplace_back(std::move(def));
261c60b897dSRiver Riddle 
262c60b897dSRiver Riddle   // If this operation is a symbol table, resolve any symbol uses.
263c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable()) {
264c60b897dSRiver Riddle     impl->symbolTableOperations.emplace_back(
265c60b897dSRiver Riddle         op, std::move(partialOpDef.symbolTable));
266c60b897dSRiver Riddle   }
267c60b897dSRiver Riddle }
268c60b897dSRiver Riddle 
269c60b897dSRiver Riddle void AsmParserState::startRegionDefinition() {
270c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
271c60b897dSRiver Riddle          "expected valid partial operation definition");
272c60b897dSRiver Riddle 
273c60b897dSRiver Riddle   // If the parent operation of this region is a symbol table, we also push a
274c60b897dSRiver Riddle   // new symbol scope.
275c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
276c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
277c60b897dSRiver Riddle     impl->symbolUseScopes.push_back(partialOpDef.symbolTable.get());
278c60b897dSRiver Riddle }
279c60b897dSRiver Riddle 
280c60b897dSRiver Riddle void AsmParserState::finalizeRegionDefinition() {
281c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
282c60b897dSRiver Riddle          "expected valid partial operation definition");
283c60b897dSRiver Riddle 
284c60b897dSRiver Riddle   // If the parent operation of this region is a symbol table, pop the symbol
285c60b897dSRiver Riddle   // scope for this region.
286c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
287c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
288c60b897dSRiver Riddle     impl->symbolUseScopes.pop_back();
289c60b897dSRiver Riddle }
290c60b897dSRiver Riddle 
291c60b897dSRiver Riddle void AsmParserState::addDefinition(Block *block, SMLoc location) {
292*59b7461cSKazu Hirata   auto [it, inserted] =
293c60b897dSRiver Riddle       impl->blocksToIdx.try_emplace(block, impl->blocks.size());
294*59b7461cSKazu Hirata   if (inserted) {
295c60b897dSRiver Riddle     impl->blocks.emplace_back(std::make_unique<BlockDefinition>(
296c60b897dSRiver Riddle         block, convertIdLocToRange(location)));
297c60b897dSRiver Riddle     return;
298c60b897dSRiver Riddle   }
299c60b897dSRiver Riddle 
300c60b897dSRiver Riddle   // If an entry already exists, this was a forward declaration that now has a
301c60b897dSRiver Riddle   // proper definition.
302c60b897dSRiver Riddle   impl->blocks[it->second]->definition.loc = convertIdLocToRange(location);
303c60b897dSRiver Riddle }
304c60b897dSRiver Riddle 
305c60b897dSRiver Riddle void AsmParserState::addDefinition(BlockArgument blockArg, SMLoc location) {
306c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(blockArg.getOwner());
307c60b897dSRiver Riddle   assert(it != impl->blocksToIdx.end() &&
308c60b897dSRiver Riddle          "expected owner block to have an entry");
309c60b897dSRiver Riddle   BlockDefinition &def = *impl->blocks[it->second];
310c60b897dSRiver Riddle   unsigned argIdx = blockArg.getArgNumber();
311c60b897dSRiver Riddle 
312c60b897dSRiver Riddle   if (def.arguments.size() <= argIdx)
313c60b897dSRiver Riddle     def.arguments.resize(argIdx + 1);
314c60b897dSRiver Riddle   def.arguments[argIdx] = SMDefinition(convertIdLocToRange(location));
315c60b897dSRiver Riddle }
316c60b897dSRiver Riddle 
3173bcc63e3SMogball void AsmParserState::addAttrAliasDefinition(StringRef name, SMRange location,
3183bcc63e3SMogball                                             Attribute value) {
319a5b584d8SMogball   auto [it, inserted] =
320a5b584d8SMogball       impl->attrAliasToIdx.try_emplace(name, impl->attrAliases.size());
321a5b584d8SMogball   // Location aliases may be referenced before they are defined.
322a5b584d8SMogball   if (inserted) {
323a5b584d8SMogball     impl->attrAliases.push_back(
3243bcc63e3SMogball         std::make_unique<AttributeAliasDefinition>(name, location, value));
325a5b584d8SMogball   } else {
3263bcc63e3SMogball     AttributeAliasDefinition &attr = *impl->attrAliases[it->second];
3273bcc63e3SMogball     attr.definition.loc = location;
3283bcc63e3SMogball     attr.value = value;
329a5b584d8SMogball   }
330a5b584d8SMogball }
331a5b584d8SMogball 
3323bcc63e3SMogball void AsmParserState::addTypeAliasDefinition(StringRef name, SMRange location,
3333bcc63e3SMogball                                             Type value) {
334604aba0cSJie Fu   [[maybe_unused]] auto [it, inserted] =
335a5b584d8SMogball       impl->typeAliasToIdx.try_emplace(name, impl->typeAliases.size());
336a5b584d8SMogball   assert(inserted && "unexpected attribute alias redefinition");
337a5b584d8SMogball   impl->typeAliases.push_back(
3383bcc63e3SMogball       std::make_unique<TypeAliasDefinition>(name, location, value));
339a5b584d8SMogball }
340a5b584d8SMogball 
341c60b897dSRiver Riddle void AsmParserState::addUses(Value value, ArrayRef<SMLoc> locations) {
342c60b897dSRiver Riddle   // Handle the case where the value is an operation result.
343f1f36124SNick Kreeger   if (OpResult result = dyn_cast<OpResult>(value)) {
344c60b897dSRiver Riddle     // Check to see if a definition for the parent operation has been recorded.
345c60b897dSRiver Riddle     // If one hasn't, we treat the provided value as a placeholder value that
346c60b897dSRiver Riddle     // will be refined further later.
347c60b897dSRiver Riddle     Operation *parentOp = result.getOwner();
348c60b897dSRiver Riddle     auto existingIt = impl->operationToIdx.find(parentOp);
349c60b897dSRiver Riddle     if (existingIt == impl->operationToIdx.end()) {
350c60b897dSRiver Riddle       impl->placeholderValueUses[value].append(locations.begin(),
351c60b897dSRiver Riddle                                                locations.end());
352c60b897dSRiver Riddle       return;
353c60b897dSRiver Riddle     }
354c60b897dSRiver Riddle 
355c60b897dSRiver Riddle     // If a definition does exist, locate the value's result group and add the
356c60b897dSRiver Riddle     // use. The result groups are ordered by increasing start index, so we just
357c60b897dSRiver Riddle     // need to find the last group that has a smaller/equal start index.
358c60b897dSRiver Riddle     unsigned resultNo = result.getResultNumber();
359c60b897dSRiver Riddle     OperationDefinition &def = *impl->operations[existingIt->second];
360c60b897dSRiver Riddle     for (auto &resultGroup : llvm::reverse(def.resultGroups)) {
361c60b897dSRiver Riddle       if (resultNo >= resultGroup.startIndex) {
362c60b897dSRiver Riddle         for (SMLoc loc : locations)
363c60b897dSRiver Riddle           resultGroup.definition.uses.push_back(convertIdLocToRange(loc));
364c60b897dSRiver Riddle         return;
365c60b897dSRiver Riddle       }
366c60b897dSRiver Riddle     }
367c60b897dSRiver Riddle     llvm_unreachable("expected valid result group for value use");
368c60b897dSRiver Riddle   }
369c60b897dSRiver Riddle 
370c60b897dSRiver Riddle   // Otherwise, this is a block argument.
3715550c821STres Popp   BlockArgument arg = cast<BlockArgument>(value);
372c60b897dSRiver Riddle   auto existingIt = impl->blocksToIdx.find(arg.getOwner());
373c60b897dSRiver Riddle   assert(existingIt != impl->blocksToIdx.end() &&
374c60b897dSRiver Riddle          "expected valid block definition for block argument");
375c60b897dSRiver Riddle   BlockDefinition &blockDef = *impl->blocks[existingIt->second];
376c60b897dSRiver Riddle   SMDefinition &argDef = blockDef.arguments[arg.getArgNumber()];
377c60b897dSRiver Riddle   for (SMLoc loc : locations)
378c60b897dSRiver Riddle     argDef.uses.emplace_back(convertIdLocToRange(loc));
379c60b897dSRiver Riddle }
380c60b897dSRiver Riddle 
381c60b897dSRiver Riddle void AsmParserState::addUses(Block *block, ArrayRef<SMLoc> locations) {
382*59b7461cSKazu Hirata   auto [it, inserted] =
383*59b7461cSKazu Hirata       impl->blocksToIdx.try_emplace(block, impl->blocks.size());
384*59b7461cSKazu Hirata   if (inserted)
385c60b897dSRiver Riddle     impl->blocks.emplace_back(std::make_unique<BlockDefinition>(block));
386c60b897dSRiver Riddle 
387c60b897dSRiver Riddle   BlockDefinition &def = *impl->blocks[it->second];
388c60b897dSRiver Riddle   for (SMLoc loc : locations)
389c60b897dSRiver Riddle     def.definition.uses.push_back(convertIdLocToRange(loc));
390c60b897dSRiver Riddle }
391c60b897dSRiver Riddle 
392c60b897dSRiver Riddle void AsmParserState::addUses(SymbolRefAttr refAttr,
393c60b897dSRiver Riddle                              ArrayRef<SMRange> locations) {
394c60b897dSRiver Riddle   // Ignore this symbol if no scopes are active.
395c60b897dSRiver Riddle   if (impl->symbolUseScopes.empty())
396c60b897dSRiver Riddle     return;
397c60b897dSRiver Riddle 
398c60b897dSRiver Riddle   assert((refAttr.getNestedReferences().size() + 1) == locations.size() &&
399c60b897dSRiver Riddle          "expected the same number of references as provided locations");
400c60b897dSRiver Riddle   (*impl->symbolUseScopes.back())[refAttr].emplace_back(locations.begin(),
401c60b897dSRiver Riddle                                                         locations.end());
402c60b897dSRiver Riddle }
403c60b897dSRiver Riddle 
404a5b584d8SMogball void AsmParserState::addAttrAliasUses(StringRef name, SMRange location) {
405a5b584d8SMogball   auto it = impl->attrAliasToIdx.find(name);
406a5b584d8SMogball   // Location aliases may be referenced before they are defined.
407a5b584d8SMogball   if (it == impl->attrAliasToIdx.end()) {
408a5b584d8SMogball     it = impl->attrAliasToIdx.try_emplace(name, impl->attrAliases.size()).first;
409a5b584d8SMogball     impl->attrAliases.push_back(
410a5b584d8SMogball         std::make_unique<AttributeAliasDefinition>(name));
411a5b584d8SMogball   }
412a5b584d8SMogball   AttributeAliasDefinition &def = *impl->attrAliases[it->second];
413a5b584d8SMogball   def.definition.uses.push_back(location);
414a5b584d8SMogball }
415a5b584d8SMogball 
416a5b584d8SMogball void AsmParserState::addTypeAliasUses(StringRef name, SMRange location) {
417a5b584d8SMogball   auto it = impl->typeAliasToIdx.find(name);
418a5b584d8SMogball   // Location aliases may be referenced before they are defined.
419a5b584d8SMogball   assert(it != impl->typeAliasToIdx.end() &&
420a5b584d8SMogball          "expected valid type alias definition");
421a5b584d8SMogball   TypeAliasDefinition &def = *impl->typeAliases[it->second];
422a5b584d8SMogball   def.definition.uses.push_back(location);
423a5b584d8SMogball }
424a5b584d8SMogball 
425c60b897dSRiver Riddle void AsmParserState::refineDefinition(Value oldValue, Value newValue) {
426c60b897dSRiver Riddle   auto it = impl->placeholderValueUses.find(oldValue);
427c60b897dSRiver Riddle   assert(it != impl->placeholderValueUses.end() &&
428c60b897dSRiver Riddle          "expected `oldValue` to be a placeholder");
429c60b897dSRiver Riddle   addUses(newValue, it->second);
430c60b897dSRiver Riddle   impl->placeholderValueUses.erase(oldValue);
431c60b897dSRiver Riddle }
432