1*c60b897dSRiver Riddle //===- AsmParserState.cpp -------------------------------------------------===//
2*c60b897dSRiver Riddle //
3*c60b897dSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c60b897dSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5*c60b897dSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c60b897dSRiver Riddle //
7*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
8*c60b897dSRiver Riddle 
9*c60b897dSRiver Riddle #include "mlir/AsmParser/AsmParserState.h"
10*c60b897dSRiver Riddle #include "mlir/IR/Operation.h"
11*c60b897dSRiver Riddle #include "mlir/IR/SymbolTable.h"
12*c60b897dSRiver Riddle #include "llvm/ADT/StringExtras.h"
13*c60b897dSRiver Riddle 
14*c60b897dSRiver Riddle using namespace mlir;
15*c60b897dSRiver Riddle 
16*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
17*c60b897dSRiver Riddle // AsmParserState::Impl
18*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
19*c60b897dSRiver Riddle 
20*c60b897dSRiver Riddle struct AsmParserState::Impl {
21*c60b897dSRiver Riddle   /// A map from a SymbolRefAttr to a range of uses.
22*c60b897dSRiver Riddle   using SymbolUseMap =
23*c60b897dSRiver Riddle       DenseMap<Attribute, SmallVector<SmallVector<SMRange>, 0>>;
24*c60b897dSRiver Riddle 
25*c60b897dSRiver Riddle   struct PartialOpDef {
PartialOpDefAsmParserState::Impl::PartialOpDef26*c60b897dSRiver Riddle     explicit PartialOpDef(const OperationName &opName) {
27*c60b897dSRiver Riddle       if (opName.hasTrait<OpTrait::SymbolTable>())
28*c60b897dSRiver Riddle         symbolTable = std::make_unique<SymbolUseMap>();
29*c60b897dSRiver Riddle     }
30*c60b897dSRiver Riddle 
31*c60b897dSRiver Riddle     /// Return if this operation is a symbol table.
isSymbolTableAsmParserState::Impl::PartialOpDef32*c60b897dSRiver Riddle     bool isSymbolTable() const { return symbolTable.get(); }
33*c60b897dSRiver Riddle 
34*c60b897dSRiver Riddle     /// If this operation is a symbol table, the following contains symbol uses
35*c60b897dSRiver Riddle     /// within this operation.
36*c60b897dSRiver Riddle     std::unique_ptr<SymbolUseMap> symbolTable;
37*c60b897dSRiver Riddle   };
38*c60b897dSRiver Riddle 
39*c60b897dSRiver Riddle   /// Resolve any symbol table uses in the IR.
40*c60b897dSRiver Riddle   void resolveSymbolUses();
41*c60b897dSRiver Riddle 
42*c60b897dSRiver Riddle   /// A mapping from operations in the input source file to their parser state.
43*c60b897dSRiver Riddle   SmallVector<std::unique_ptr<OperationDefinition>> operations;
44*c60b897dSRiver Riddle   DenseMap<Operation *, unsigned> operationToIdx;
45*c60b897dSRiver Riddle 
46*c60b897dSRiver Riddle   /// A mapping from blocks in the input source file to their parser state.
47*c60b897dSRiver Riddle   SmallVector<std::unique_ptr<BlockDefinition>> blocks;
48*c60b897dSRiver Riddle   DenseMap<Block *, unsigned> blocksToIdx;
49*c60b897dSRiver Riddle 
50*c60b897dSRiver Riddle   /// A set of value definitions that are placeholders for forward references.
51*c60b897dSRiver Riddle   /// This map should be empty if the parser finishes successfully.
52*c60b897dSRiver Riddle   DenseMap<Value, SmallVector<SMLoc>> placeholderValueUses;
53*c60b897dSRiver Riddle 
54*c60b897dSRiver Riddle   /// The symbol table operations within the IR.
55*c60b897dSRiver Riddle   SmallVector<std::pair<Operation *, std::unique_ptr<SymbolUseMap>>>
56*c60b897dSRiver Riddle       symbolTableOperations;
57*c60b897dSRiver Riddle 
58*c60b897dSRiver Riddle   /// A stack of partial operation definitions that have been started but not
59*c60b897dSRiver Riddle   /// yet finalized.
60*c60b897dSRiver Riddle   SmallVector<PartialOpDef> partialOperations;
61*c60b897dSRiver Riddle 
62*c60b897dSRiver Riddle   /// A stack of symbol use scopes. This is used when collecting symbol table
63*c60b897dSRiver Riddle   /// uses during parsing.
64*c60b897dSRiver Riddle   SmallVector<SymbolUseMap *> symbolUseScopes;
65*c60b897dSRiver Riddle 
66*c60b897dSRiver Riddle   /// A symbol table containing all of the symbol table operations in the IR.
67*c60b897dSRiver Riddle   SymbolTableCollection symbolTable;
68*c60b897dSRiver Riddle };
69*c60b897dSRiver Riddle 
resolveSymbolUses()70*c60b897dSRiver Riddle void AsmParserState::Impl::resolveSymbolUses() {
71*c60b897dSRiver Riddle   SmallVector<Operation *> symbolOps;
72*c60b897dSRiver Riddle   for (auto &opAndUseMapIt : symbolTableOperations) {
73*c60b897dSRiver Riddle     for (auto &it : *opAndUseMapIt.second) {
74*c60b897dSRiver Riddle       symbolOps.clear();
75*c60b897dSRiver Riddle       if (failed(symbolTable.lookupSymbolIn(
76*c60b897dSRiver Riddle               opAndUseMapIt.first, it.first.cast<SymbolRefAttr>(), symbolOps)))
77*c60b897dSRiver Riddle         continue;
78*c60b897dSRiver Riddle 
79*c60b897dSRiver Riddle       for (ArrayRef<SMRange> useRange : it.second) {
80*c60b897dSRiver Riddle         for (const auto &symIt : llvm::zip(symbolOps, useRange)) {
81*c60b897dSRiver Riddle           auto opIt = operationToIdx.find(std::get<0>(symIt));
82*c60b897dSRiver Riddle           if (opIt != operationToIdx.end())
83*c60b897dSRiver Riddle             operations[opIt->second]->symbolUses.push_back(std::get<1>(symIt));
84*c60b897dSRiver Riddle         }
85*c60b897dSRiver Riddle       }
86*c60b897dSRiver Riddle     }
87*c60b897dSRiver Riddle   }
88*c60b897dSRiver Riddle }
89*c60b897dSRiver Riddle 
90*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
91*c60b897dSRiver Riddle // AsmParserState
92*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
93*c60b897dSRiver Riddle 
AsmParserState()94*c60b897dSRiver Riddle AsmParserState::AsmParserState() : impl(std::make_unique<Impl>()) {}
95*c60b897dSRiver Riddle AsmParserState::~AsmParserState() = default;
operator =(AsmParserState && other)96*c60b897dSRiver Riddle AsmParserState &AsmParserState::operator=(AsmParserState &&other) {
97*c60b897dSRiver Riddle   impl = std::move(other.impl);
98*c60b897dSRiver Riddle   return *this;
99*c60b897dSRiver Riddle }
100*c60b897dSRiver Riddle 
101*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
102*c60b897dSRiver Riddle // Access State
103*c60b897dSRiver Riddle 
getBlockDefs() const104*c60b897dSRiver Riddle auto AsmParserState::getBlockDefs() const -> iterator_range<BlockDefIterator> {
105*c60b897dSRiver Riddle   return llvm::make_pointee_range(llvm::makeArrayRef(impl->blocks));
106*c60b897dSRiver Riddle }
107*c60b897dSRiver Riddle 
getBlockDef(Block * block) const108*c60b897dSRiver Riddle auto AsmParserState::getBlockDef(Block *block) const
109*c60b897dSRiver Riddle     -> const BlockDefinition * {
110*c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(block);
111*c60b897dSRiver Riddle   return it == impl->blocksToIdx.end() ? nullptr : &*impl->blocks[it->second];
112*c60b897dSRiver Riddle }
113*c60b897dSRiver Riddle 
getOpDefs() const114*c60b897dSRiver Riddle auto AsmParserState::getOpDefs() const -> iterator_range<OperationDefIterator> {
115*c60b897dSRiver Riddle   return llvm::make_pointee_range(llvm::makeArrayRef(impl->operations));
116*c60b897dSRiver Riddle }
117*c60b897dSRiver Riddle 
getOpDef(Operation * op) const118*c60b897dSRiver Riddle auto AsmParserState::getOpDef(Operation *op) const
119*c60b897dSRiver Riddle     -> const OperationDefinition * {
120*c60b897dSRiver Riddle   auto it = impl->operationToIdx.find(op);
121*c60b897dSRiver Riddle   return it == impl->operationToIdx.end() ? nullptr
122*c60b897dSRiver Riddle                                           : &*impl->operations[it->second];
123*c60b897dSRiver Riddle }
124*c60b897dSRiver Riddle 
125*c60b897dSRiver Riddle /// Lex a string token whose contents start at the given `curPtr`. Returns the
126*c60b897dSRiver Riddle /// position at the end of the string, after a terminal or invalid character
127*c60b897dSRiver Riddle /// (e.g. `"` or `\0`).
lexLocStringTok(const char * curPtr)128*c60b897dSRiver Riddle static const char *lexLocStringTok(const char *curPtr) {
129*c60b897dSRiver Riddle   while (char c = *curPtr++) {
130*c60b897dSRiver Riddle     // Check for various terminal characters.
131*c60b897dSRiver Riddle     if (StringRef("\"\n\v\f").contains(c))
132*c60b897dSRiver Riddle       return curPtr;
133*c60b897dSRiver Riddle 
134*c60b897dSRiver Riddle     // Check for escape sequences.
135*c60b897dSRiver Riddle     if (c == '\\') {
136*c60b897dSRiver Riddle       // Check a few known escapes and \xx hex digits.
137*c60b897dSRiver Riddle       if (*curPtr == '"' || *curPtr == '\\' || *curPtr == 'n' || *curPtr == 't')
138*c60b897dSRiver Riddle         ++curPtr;
139*c60b897dSRiver Riddle       else if (llvm::isHexDigit(*curPtr) && llvm::isHexDigit(curPtr[1]))
140*c60b897dSRiver Riddle         curPtr += 2;
141*c60b897dSRiver Riddle       else
142*c60b897dSRiver Riddle         return curPtr;
143*c60b897dSRiver Riddle     }
144*c60b897dSRiver Riddle   }
145*c60b897dSRiver Riddle 
146*c60b897dSRiver Riddle   // If we hit this point, we've reached the end of the buffer. Update the end
147*c60b897dSRiver Riddle   // pointer to not point past the buffer.
148*c60b897dSRiver Riddle   return curPtr - 1;
149*c60b897dSRiver Riddle }
150*c60b897dSRiver Riddle 
convertIdLocToRange(SMLoc loc)151*c60b897dSRiver Riddle SMRange AsmParserState::convertIdLocToRange(SMLoc loc) {
152*c60b897dSRiver Riddle   if (!loc.isValid())
153*c60b897dSRiver Riddle     return SMRange();
154*c60b897dSRiver Riddle   const char *curPtr = loc.getPointer();
155*c60b897dSRiver Riddle 
156*c60b897dSRiver Riddle   // Check if this is a string token.
157*c60b897dSRiver Riddle   if (*curPtr == '"') {
158*c60b897dSRiver Riddle     curPtr = lexLocStringTok(curPtr + 1);
159*c60b897dSRiver Riddle 
160*c60b897dSRiver Riddle     // Otherwise, default to handling an identifier.
161*c60b897dSRiver Riddle   } else {
162*c60b897dSRiver Riddle     // Return if the given character is a valid identifier character.
163*c60b897dSRiver Riddle     auto isIdentifierChar = [](char c) {
164*c60b897dSRiver Riddle       return isalnum(c) || c == '$' || c == '.' || c == '_' || c == '-';
165*c60b897dSRiver Riddle     };
166*c60b897dSRiver Riddle 
167*c60b897dSRiver Riddle     while (*curPtr && isIdentifierChar(*(++curPtr)))
168*c60b897dSRiver Riddle       continue;
169*c60b897dSRiver Riddle   }
170*c60b897dSRiver Riddle 
171*c60b897dSRiver Riddle   return SMRange(loc, SMLoc::getFromPointer(curPtr));
172*c60b897dSRiver Riddle }
173*c60b897dSRiver Riddle 
174*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
175*c60b897dSRiver Riddle // Populate State
176*c60b897dSRiver Riddle 
initialize(Operation * topLevelOp)177*c60b897dSRiver Riddle void AsmParserState::initialize(Operation *topLevelOp) {
178*c60b897dSRiver Riddle   startOperationDefinition(topLevelOp->getName());
179*c60b897dSRiver Riddle 
180*c60b897dSRiver Riddle   // If the top-level operation is a symbol table, push a new symbol scope.
181*c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
182*c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
183*c60b897dSRiver Riddle     impl->symbolUseScopes.push_back(partialOpDef.symbolTable.get());
184*c60b897dSRiver Riddle }
185*c60b897dSRiver Riddle 
finalize(Operation * topLevelOp)186*c60b897dSRiver Riddle void AsmParserState::finalize(Operation *topLevelOp) {
187*c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
188*c60b897dSRiver Riddle          "expected valid partial operation definition");
189*c60b897dSRiver Riddle   Impl::PartialOpDef partialOpDef = impl->partialOperations.pop_back_val();
190*c60b897dSRiver Riddle 
191*c60b897dSRiver Riddle   // If this operation is a symbol table, resolve any symbol uses.
192*c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable()) {
193*c60b897dSRiver Riddle     impl->symbolTableOperations.emplace_back(
194*c60b897dSRiver Riddle         topLevelOp, std::move(partialOpDef.symbolTable));
195*c60b897dSRiver Riddle   }
196*c60b897dSRiver Riddle   impl->resolveSymbolUses();
197*c60b897dSRiver Riddle }
198*c60b897dSRiver Riddle 
startOperationDefinition(const OperationName & opName)199*c60b897dSRiver Riddle void AsmParserState::startOperationDefinition(const OperationName &opName) {
200*c60b897dSRiver Riddle   impl->partialOperations.emplace_back(opName);
201*c60b897dSRiver Riddle }
202*c60b897dSRiver Riddle 
finalizeOperationDefinition(Operation * op,SMRange nameLoc,SMLoc endLoc,ArrayRef<std::pair<unsigned,SMLoc>> resultGroups)203*c60b897dSRiver Riddle void AsmParserState::finalizeOperationDefinition(
204*c60b897dSRiver Riddle     Operation *op, SMRange nameLoc, SMLoc endLoc,
205*c60b897dSRiver Riddle     ArrayRef<std::pair<unsigned, SMLoc>> resultGroups) {
206*c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
207*c60b897dSRiver Riddle          "expected valid partial operation definition");
208*c60b897dSRiver Riddle   Impl::PartialOpDef partialOpDef = impl->partialOperations.pop_back_val();
209*c60b897dSRiver Riddle 
210*c60b897dSRiver Riddle   // Build the full operation definition.
211*c60b897dSRiver Riddle   std::unique_ptr<OperationDefinition> def =
212*c60b897dSRiver Riddle       std::make_unique<OperationDefinition>(op, nameLoc, endLoc);
213*c60b897dSRiver Riddle   for (auto &resultGroup : resultGroups)
214*c60b897dSRiver Riddle     def->resultGroups.emplace_back(resultGroup.first,
215*c60b897dSRiver Riddle                                    convertIdLocToRange(resultGroup.second));
216*c60b897dSRiver Riddle   impl->operationToIdx.try_emplace(op, impl->operations.size());
217*c60b897dSRiver Riddle   impl->operations.emplace_back(std::move(def));
218*c60b897dSRiver Riddle 
219*c60b897dSRiver Riddle   // If this operation is a symbol table, resolve any symbol uses.
220*c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable()) {
221*c60b897dSRiver Riddle     impl->symbolTableOperations.emplace_back(
222*c60b897dSRiver Riddle         op, std::move(partialOpDef.symbolTable));
223*c60b897dSRiver Riddle   }
224*c60b897dSRiver Riddle }
225*c60b897dSRiver Riddle 
startRegionDefinition()226*c60b897dSRiver Riddle void AsmParserState::startRegionDefinition() {
227*c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
228*c60b897dSRiver Riddle          "expected valid partial operation definition");
229*c60b897dSRiver Riddle 
230*c60b897dSRiver Riddle   // If the parent operation of this region is a symbol table, we also push a
231*c60b897dSRiver Riddle   // new symbol scope.
232*c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
233*c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
234*c60b897dSRiver Riddle     impl->symbolUseScopes.push_back(partialOpDef.symbolTable.get());
235*c60b897dSRiver Riddle }
236*c60b897dSRiver Riddle 
finalizeRegionDefinition()237*c60b897dSRiver Riddle void AsmParserState::finalizeRegionDefinition() {
238*c60b897dSRiver Riddle   assert(!impl->partialOperations.empty() &&
239*c60b897dSRiver Riddle          "expected valid partial operation definition");
240*c60b897dSRiver Riddle 
241*c60b897dSRiver Riddle   // If the parent operation of this region is a symbol table, pop the symbol
242*c60b897dSRiver Riddle   // scope for this region.
243*c60b897dSRiver Riddle   Impl::PartialOpDef &partialOpDef = impl->partialOperations.back();
244*c60b897dSRiver Riddle   if (partialOpDef.isSymbolTable())
245*c60b897dSRiver Riddle     impl->symbolUseScopes.pop_back();
246*c60b897dSRiver Riddle }
247*c60b897dSRiver Riddle 
addDefinition(Block * block,SMLoc location)248*c60b897dSRiver Riddle void AsmParserState::addDefinition(Block *block, SMLoc location) {
249*c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(block);
250*c60b897dSRiver Riddle   if (it == impl->blocksToIdx.end()) {
251*c60b897dSRiver Riddle     impl->blocksToIdx.try_emplace(block, impl->blocks.size());
252*c60b897dSRiver Riddle     impl->blocks.emplace_back(std::make_unique<BlockDefinition>(
253*c60b897dSRiver Riddle         block, convertIdLocToRange(location)));
254*c60b897dSRiver Riddle     return;
255*c60b897dSRiver Riddle   }
256*c60b897dSRiver Riddle 
257*c60b897dSRiver Riddle   // If an entry already exists, this was a forward declaration that now has a
258*c60b897dSRiver Riddle   // proper definition.
259*c60b897dSRiver Riddle   impl->blocks[it->second]->definition.loc = convertIdLocToRange(location);
260*c60b897dSRiver Riddle }
261*c60b897dSRiver Riddle 
addDefinition(BlockArgument blockArg,SMLoc location)262*c60b897dSRiver Riddle void AsmParserState::addDefinition(BlockArgument blockArg, SMLoc location) {
263*c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(blockArg.getOwner());
264*c60b897dSRiver Riddle   assert(it != impl->blocksToIdx.end() &&
265*c60b897dSRiver Riddle          "expected owner block to have an entry");
266*c60b897dSRiver Riddle   BlockDefinition &def = *impl->blocks[it->second];
267*c60b897dSRiver Riddle   unsigned argIdx = blockArg.getArgNumber();
268*c60b897dSRiver Riddle 
269*c60b897dSRiver Riddle   if (def.arguments.size() <= argIdx)
270*c60b897dSRiver Riddle     def.arguments.resize(argIdx + 1);
271*c60b897dSRiver Riddle   def.arguments[argIdx] = SMDefinition(convertIdLocToRange(location));
272*c60b897dSRiver Riddle }
273*c60b897dSRiver Riddle 
addUses(Value value,ArrayRef<SMLoc> locations)274*c60b897dSRiver Riddle void AsmParserState::addUses(Value value, ArrayRef<SMLoc> locations) {
275*c60b897dSRiver Riddle   // Handle the case where the value is an operation result.
276*c60b897dSRiver Riddle   if (OpResult result = value.dyn_cast<OpResult>()) {
277*c60b897dSRiver Riddle     // Check to see if a definition for the parent operation has been recorded.
278*c60b897dSRiver Riddle     // If one hasn't, we treat the provided value as a placeholder value that
279*c60b897dSRiver Riddle     // will be refined further later.
280*c60b897dSRiver Riddle     Operation *parentOp = result.getOwner();
281*c60b897dSRiver Riddle     auto existingIt = impl->operationToIdx.find(parentOp);
282*c60b897dSRiver Riddle     if (existingIt == impl->operationToIdx.end()) {
283*c60b897dSRiver Riddle       impl->placeholderValueUses[value].append(locations.begin(),
284*c60b897dSRiver Riddle                                                locations.end());
285*c60b897dSRiver Riddle       return;
286*c60b897dSRiver Riddle     }
287*c60b897dSRiver Riddle 
288*c60b897dSRiver Riddle     // If a definition does exist, locate the value's result group and add the
289*c60b897dSRiver Riddle     // use. The result groups are ordered by increasing start index, so we just
290*c60b897dSRiver Riddle     // need to find the last group that has a smaller/equal start index.
291*c60b897dSRiver Riddle     unsigned resultNo = result.getResultNumber();
292*c60b897dSRiver Riddle     OperationDefinition &def = *impl->operations[existingIt->second];
293*c60b897dSRiver Riddle     for (auto &resultGroup : llvm::reverse(def.resultGroups)) {
294*c60b897dSRiver Riddle       if (resultNo >= resultGroup.startIndex) {
295*c60b897dSRiver Riddle         for (SMLoc loc : locations)
296*c60b897dSRiver Riddle           resultGroup.definition.uses.push_back(convertIdLocToRange(loc));
297*c60b897dSRiver Riddle         return;
298*c60b897dSRiver Riddle       }
299*c60b897dSRiver Riddle     }
300*c60b897dSRiver Riddle     llvm_unreachable("expected valid result group for value use");
301*c60b897dSRiver Riddle   }
302*c60b897dSRiver Riddle 
303*c60b897dSRiver Riddle   // Otherwise, this is a block argument.
304*c60b897dSRiver Riddle   BlockArgument arg = value.cast<BlockArgument>();
305*c60b897dSRiver Riddle   auto existingIt = impl->blocksToIdx.find(arg.getOwner());
306*c60b897dSRiver Riddle   assert(existingIt != impl->blocksToIdx.end() &&
307*c60b897dSRiver Riddle          "expected valid block definition for block argument");
308*c60b897dSRiver Riddle   BlockDefinition &blockDef = *impl->blocks[existingIt->second];
309*c60b897dSRiver Riddle   SMDefinition &argDef = blockDef.arguments[arg.getArgNumber()];
310*c60b897dSRiver Riddle   for (SMLoc loc : locations)
311*c60b897dSRiver Riddle     argDef.uses.emplace_back(convertIdLocToRange(loc));
312*c60b897dSRiver Riddle }
313*c60b897dSRiver Riddle 
addUses(Block * block,ArrayRef<SMLoc> locations)314*c60b897dSRiver Riddle void AsmParserState::addUses(Block *block, ArrayRef<SMLoc> locations) {
315*c60b897dSRiver Riddle   auto it = impl->blocksToIdx.find(block);
316*c60b897dSRiver Riddle   if (it == impl->blocksToIdx.end()) {
317*c60b897dSRiver Riddle     it = impl->blocksToIdx.try_emplace(block, impl->blocks.size()).first;
318*c60b897dSRiver Riddle     impl->blocks.emplace_back(std::make_unique<BlockDefinition>(block));
319*c60b897dSRiver Riddle   }
320*c60b897dSRiver Riddle 
321*c60b897dSRiver Riddle   BlockDefinition &def = *impl->blocks[it->second];
322*c60b897dSRiver Riddle   for (SMLoc loc : locations)
323*c60b897dSRiver Riddle     def.definition.uses.push_back(convertIdLocToRange(loc));
324*c60b897dSRiver Riddle }
325*c60b897dSRiver Riddle 
addUses(SymbolRefAttr refAttr,ArrayRef<SMRange> locations)326*c60b897dSRiver Riddle void AsmParserState::addUses(SymbolRefAttr refAttr,
327*c60b897dSRiver Riddle                              ArrayRef<SMRange> locations) {
328*c60b897dSRiver Riddle   // Ignore this symbol if no scopes are active.
329*c60b897dSRiver Riddle   if (impl->symbolUseScopes.empty())
330*c60b897dSRiver Riddle     return;
331*c60b897dSRiver Riddle 
332*c60b897dSRiver Riddle   assert((refAttr.getNestedReferences().size() + 1) == locations.size() &&
333*c60b897dSRiver Riddle          "expected the same number of references as provided locations");
334*c60b897dSRiver Riddle   (*impl->symbolUseScopes.back())[refAttr].emplace_back(locations.begin(),
335*c60b897dSRiver Riddle                                                         locations.end());
336*c60b897dSRiver Riddle }
337*c60b897dSRiver Riddle 
refineDefinition(Value oldValue,Value newValue)338*c60b897dSRiver Riddle void AsmParserState::refineDefinition(Value oldValue, Value newValue) {
339*c60b897dSRiver Riddle   auto it = impl->placeholderValueUses.find(oldValue);
340*c60b897dSRiver Riddle   assert(it != impl->placeholderValueUses.end() &&
341*c60b897dSRiver Riddle          "expected `oldValue` to be a placeholder");
342*c60b897dSRiver Riddle   addUses(newValue, it->second);
343*c60b897dSRiver Riddle   impl->placeholderValueUses.erase(oldValue);
344*c60b897dSRiver Riddle }
345