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