diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 0ff6e1b35e72..b7a300bd8815 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -229,7 +229,47 @@ Example: See [this issue](https://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files. -## 13. Recommended reading +## 13. Associative Containers + +1. Prefer `std::unordered_map` / `std::unordered_set` over `std::map` / `std::set` when iteration order does not matter (i.e. the container is used only for lookup, membership testing, or deduplication). +2. Avoid multiple sequential lookups on the same key. Use a single `find` and reuse the iterator: + +Yes: +```cpp +if (auto it = m_map.find(key); it != m_map.end()) + use(it->second); +``` + +No: +```cpp +if (m_map.count(key)) + use(m_map.at(key)); +``` + +3. For "insert if absent" patterns, prefer `insert().second` or `try_emplace` over `count` + `insert`/`operator[]`: + +Yes: +```cpp +if (auto [it, inserted] = m_set.insert(value); inserted) + onNewElement(); + +auto [it, inserted] = m_map.try_emplace(key); +if (inserted) + it->second = computeValue(); +``` + +No: +```cpp +if (!m_set.count(value)) +{ + m_set.insert(value); + onNewElement(); +} +``` + +4. Use `std::erase_if` (C++20) instead of manual erase-while-iterate loops on associative containers. + +## 14. Recommended reading - Herb Sutter and Bjarne Stroustrup: - [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index ef6c0bec9cce..2ebdcbecfa8d 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -741,15 +741,18 @@ std::shared_ptr Assembly::sharedSourceName(std::string const& AssemblyItem Assembly::namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID) { assertThrow(!_name.empty(), AssemblyException, "Empty named tag."); - if (m_namedTags.count(_name)) + if (auto it = m_namedTags.find(_name); it != m_namedTags.end()) { - assertThrow(m_namedTags.at(_name).params == _params, AssemblyException, ""); - assertThrow(m_namedTags.at(_name).returns == _returns, AssemblyException, ""); - assertThrow(m_namedTags.at(_name).sourceID == _sourceID, AssemblyException, ""); + assertThrow(it->second.params == _params, AssemblyException, ""); + assertThrow(it->second.returns == _returns, AssemblyException, ""); + assertThrow(it->second.sourceID == _sourceID, AssemblyException, ""); + return AssemblyItem{Tag, it->second.id}; } - else - m_namedTags[_name] = {static_cast(newTag().data()), _sourceID, _params, _returns}; - return AssemblyItem{Tag, m_namedTags.at(_name).id}; + auto [it, _] = m_namedTags.emplace( + _name, + NamedTagInfo{static_cast(newTag().data()), _sourceID, _params, _returns} + ); + return AssemblyItem{Tag, it->second.id}; } AssemblyItem Assembly::newFunctionCall(uint16_t _functionID) const diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index f931c438e38a..66f061cef47d 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -39,6 +39,7 @@ #include #include #include +#include #include namespace solidity::evmasm @@ -303,7 +304,7 @@ class Assembly size_t returns; }; - std::map m_namedTags; + std::unordered_map m_namedTags; std::map m_data; /// Data that is appended to the very end of the contract. bytes m_auxiliaryData; diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 50aa3f009616..5bfe74dc676c 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -179,7 +179,7 @@ AssemblyItems CSECodeGenerator::generateCode( // generate the target stack elements for (auto const& targetItem: m_targetStack) { - if (m_stack.count(targetItem.first) && m_stack.at(targetItem.first) == targetItem.second) + if (auto it = m_stack.find(targetItem.first); it != m_stack.end() && it->second == targetItem.second) continue; // already there generateClassElement(targetItem.second); assertThrow(!m_classPositions[targetItem.second].empty(), OptimizerException, ""); @@ -427,12 +427,13 @@ void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) int CSECodeGenerator::classElementPosition(Id _id) const { + auto it = m_classPositions.find(_id); assertThrow( - m_classPositions.count(_id) && !m_classPositions.at(_id).empty(), + it != m_classPositions.end() && !it->second.empty(), OptimizerException, "Element requested but is not present." ); - return *max_element(m_classPositions.at(_id).begin(), m_classPositions.at(_id).end()); + return *max_element(it->second.begin(), it->second.end()); } bool CSECodeGenerator::canBeRemoved(Id _element, Id _result, int _fromPosition) @@ -443,8 +444,11 @@ bool CSECodeGenerator::canBeRemoved(Id _element, Id _result, int _fromPosition) bool haveCopy = m_classPositions.at(_element).size() > 1; if (m_finalClasses.count(_element)) + { // It is part of the target stack. It can be removed if it is a copy that is not in the target position. - return haveCopy && (!m_targetStack.count(_fromPosition) || m_targetStack[_fromPosition] != _element); + auto tsIt = m_targetStack.find(_fromPosition); + return haveCopy && (tsIt == m_targetStack.end() || tsIt->second != _element); + } else if (!haveCopy) { // Can be removed unless it is needed by a class that has not been computed yet. diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp index 5b73fb6d5b21..a25cd1e68569 100644 --- a/libevmasm/ControlFlowGraph.cpp +++ b/libevmasm/ControlFlowGraph.cpp @@ -122,13 +122,16 @@ void ControlFlowGraph::resolveNextLinks() { case BasicBlock::EndType::JUMPI: case BasicBlock::EndType::HANDOVER: + { + auto it = blockByBeginPos.find(block.end); assertThrow( - blockByBeginPos.count(block.end), + it != blockByBeginPos.end(), OptimizerException, "Successor block not found." ); - block.next = blockByBeginPos.at(block.end); + block.next = it->second; break; + } default: break; } @@ -193,15 +196,22 @@ void ControlFlowGraph::setPrevLinks() if (push.type() != PushTag) continue; BlockId nextId(push.data()); - if (m_blocks.count(nextId) && m_blocks.at(nextId).prev) + auto nextIt = m_blocks.find(nextId); + if (nextIt != m_blocks.end() && nextIt->second.prev) continue; bool hasLoop = false; - for (BlockId id = nextId; id && m_blocks.count(id) && !hasLoop; id = m_blocks.at(id).next) + for (BlockId id = nextId; id && !hasLoop;) + { + auto loopIt = m_blocks.find(id); + if (loopIt == m_blocks.end()) + break; hasLoop = (id == blockId); - if (hasLoop || !m_blocks.count(nextId)) + id = loopIt->second.next; + } + if (hasLoop || nextIt == m_blocks.end()) continue; - m_blocks[nextId].prev = blockId; + nextIt->second.prev = blockId; block.next = nextId; block.end -= 2; assertThrow( @@ -244,9 +254,10 @@ void ControlFlowGraph::gatherKnowledge() workQueue.pop_back(); //@todo we might have to do something like incrementing the sequence number for each JUMPDEST assertThrow(!!item.blockId, OptimizerException, ""); - if (!m_blocks.count(item.blockId)) + auto blockIt = m_blocks.find(item.blockId); + if (blockIt == m_blocks.end()) continue; // too bad, we do not know the tag, probably an invalid jump - BasicBlock& block = m_blocks.at(item.blockId); + BasicBlock& block = blockIt->second; KnownStatePointer state = item.state; if (block.startState) { diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 6e1a00465b26..e513598d813c 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -215,20 +215,19 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool /// _this which is not in or not equal to the value in _other. template void intersect(Mapping& _this, Mapping const& _other) { - for (auto it = _this.begin(); it != _this.end();) - if (_other.count(it->first) && _other.at(it->first) == it->second) - ++it; - else - it = _this.erase(it); + std::erase_if(_this, [&](auto const& elem) { + auto it = _other.find(elem.first); + return it == _other.end() || it->second != elem.second; + }); } void KnownState::reduceToCommonKnowledge(KnownState const& _other, bool _combineSequenceNumbers) { int stackDiff = m_stackHeight - _other.m_stackHeight; for (auto it = m_stackElements.begin(); it != m_stackElements.end();) - if (_other.m_stackElements.count(it->first - stackDiff)) + if (auto otherIt = _other.m_stackElements.find(it->first - stackDiff); otherIt != _other.m_stackElements.end()) { - Id other = _other.m_stackElements.at(it->first - stackDiff); + Id other = otherIt->second; if (it->second == other) ++it; else @@ -279,9 +278,8 @@ bool KnownState::operator==(KnownState const& _other) const ExpressionClasses::Id KnownState::stackElement(int _stackHeight, langutil::DebugData::ConstPtr _debugData) { - if (m_stackElements.count(_stackHeight)) - return m_stackElements.at(_stackHeight); - // Stack element not found (not assigned yet), create new unknown equivalence class. + if (auto it = m_stackElements.find(_stackHeight); it != m_stackElements.end()) + return it->second; return m_stackElements[_stackHeight] = m_expressionClasses->find(AssemblyItem(UndefinedItem, _stackHeight, std::move(_debugData))); } @@ -325,8 +323,7 @@ KnownState::StoreOperation KnownState::storeInStorage( langutil::DebugData::ConstPtr _debugData ) { - if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) - // do not execute the storage if we know that the value is already there + if (auto it = m_storageContent.find(_slot); it != m_storageContent.end() && it->second == _value) return StoreOperation(); m_sequenceNumber++; decltype(m_storageContent) storageContents; @@ -350,8 +347,8 @@ KnownState::StoreOperation KnownState::storeInStorage( ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, langutil::DebugData::ConstPtr _debugData) { - if (m_storageContent.count(_slot)) - return m_storageContent.at(_slot); + if (auto it = m_storageContent.find(_slot); it != m_storageContent.end()) + return it->second; AssemblyItem item(Instruction::SLOAD, std::move(_debugData)); return m_storageContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber); @@ -359,8 +356,7 @@ ExpressionClasses::Id KnownState::loadFromStorage(Id _slot, langutil::DebugData: KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, langutil::DebugData::ConstPtr _debugData) { - if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) - // do not execute the store if we know that the value is already there + if (auto it = m_memoryContent.find(_slot); it != m_memoryContent.end() && it->second == _value) return StoreOperation(); m_sequenceNumber++; decltype(m_memoryContent) memoryContents; @@ -381,8 +377,8 @@ KnownState::StoreOperation KnownState::storeInMemory(Id _slot, Id _value, langut ExpressionClasses::Id KnownState::loadFromMemory(Id _slot, langutil::DebugData::ConstPtr _debugData) { - if (m_memoryContent.count(_slot)) - return m_memoryContent.at(_slot); + if (auto it = m_memoryContent.find(_slot); it != m_memoryContent.end()) + return it->second; AssemblyItem item(Instruction::MLOAD, std::move(_debugData)); return m_memoryContent[_slot] = m_expressionClasses->find(item, {_slot}, true, m_sequenceNumber); @@ -410,8 +406,8 @@ KnownState::Id KnownState::applyKeccak256( ); arguments.push_back(loadFromMemory(slot, _debugData)); } - if (m_knownKeccak256Hashes.count({arguments, length})) - return m_knownKeccak256Hashes.at({arguments, length}); + if (auto it = m_knownKeccak256Hashes.find({arguments, length}); it != m_knownKeccak256Hashes.end()) + return it->second; Id v; // If all arguments are known constants, compute the Keccak-256 here if (all_of(arguments.begin(), arguments.end(), [this](Id _a) { return !!m_expressionClasses->knownConstant(_a); })) @@ -429,8 +425,8 @@ KnownState::Id KnownState::applyKeccak256( std::set KnownState::tagsInExpression(KnownState::Id _expressionId) { - if (m_tagUnions.left.count(_expressionId)) - return m_tagUnions.left.at(_expressionId); + if (auto it = m_tagUnions.left.find(_expressionId); it != m_tagUnions.left.end()) + return it->second; // Might be a tag, then return the set of itself. ExpressionClasses::Expression expr = m_expressionClasses->representative(_expressionId); if (expr.item && expr.item->type() == PushTag) @@ -441,8 +437,8 @@ std::set KnownState::tagsInExpression(KnownState::Id _expressionId) KnownState::Id KnownState::tagUnion(std::set _tags) { - if (m_tagUnions.right.count(_tags)) - return m_tagUnions.right.at(_tags); + if (auto it = m_tagUnions.right.find(_tags); it != m_tagUnions.right.end()) + return it->second; else { Id id = m_expressionClasses->newClass(langutil::DebugData::create()); diff --git a/libevmasm/PathGasMeter.cpp b/libevmasm/PathGasMeter.cpp index 2acafea22cd4..450a93dc968e 100644 --- a/libevmasm/PathGasMeter.cpp +++ b/libevmasm/PathGasMeter.cpp @@ -53,12 +53,13 @@ GasMeter::GasConsumption PathGasMeter::estimateMax( void PathGasMeter::queue(std::unique_ptr&& _newPath) { - if ( - m_highestGasUsagePerJumpdest.count(_newPath->index) && - _newPath->gas < m_highestGasUsagePerJumpdest.at(_newPath->index) - ) - return; - m_highestGasUsagePerJumpdest[_newPath->index] = _newPath->gas; + auto [it, inserted] = m_highestGasUsagePerJumpdest.emplace(_newPath->index, _newPath->gas); + if (!inserted) + { + if (_newPath->gas < it->second) + return; + it->second = _newPath->gas; + } m_queue[_newPath->index] = std::move(_newPath); } @@ -122,8 +123,8 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem() { auto newPath = std::make_unique(); newPath->index = m_items.size(); - if (m_tagPositions.count(tag)) - newPath->index = m_tagPositions.at(tag); + if (auto it = m_tagPositions.find(tag); it != m_tagPositions.end()) + newPath->index = it->second; newPath->gas = gas; newPath->largestMemoryAccess = meter.largestMemoryAccess(); newPath->state = state->copy(); diff --git a/libevmasm/PathGasMeter.h b/libevmasm/PathGasMeter.h index ecac17cac2f8..6e388f5ec5ad 100644 --- a/libevmasm/PathGasMeter.h +++ b/libevmasm/PathGasMeter.h @@ -26,7 +26,8 @@ #include -#include +#include +#include #include #include @@ -41,7 +42,7 @@ struct GasPath std::shared_ptr state; u256 largestMemoryAccess; GasMeter::GasConsumption gas; - std::set visitedJumpdests; + std::unordered_set visitedJumpdests; }; /** @@ -77,7 +78,7 @@ class PathGasMeter /// Map of jumpdest -> gas path, so not really a queue. We only have one queued up /// item per jumpdest, because of the behaviour of `queue` above. std::map> m_queue; - std::map m_highestGasUsagePerJumpdest; + std::unordered_map m_highestGasUsagePerJumpdest; std::map m_tagPositions; AssemblyItems const& m_items; langutil::EVMVersion m_evmVersion; diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 7cd7c5e962ef..1f3ffdd66167 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -267,11 +267,13 @@ struct SwapComparison: SimplePeepholeOptimizerMethod if ( _swap == Instruction::SWAP1 && - _op.type() == Operation && - swappableOps.count(_op.instruction()) + _op.type() == Operation ) { - *_out = swappableOps.at(_op.instruction()); + auto it = swappableOps.find(_op.instruction()); + if (it == swappableOps.end()) + return false; + *_out = it->second; return true; } else diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 11d8e84c6601..c45710f11ef1 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -547,8 +547,8 @@ void ControlFlowBuilder::operator()(yul::Identifier const& _identifier) { solAssert(m_currentNode && m_inlineAssembly, ""); auto const& externalReferences = m_inlineAssembly->annotation().externalReferences; - if (externalReferences.count(&_identifier)) - if (auto const* declaration = dynamic_cast(externalReferences.at(&_identifier).declaration)) + if (auto it = externalReferences.find(&_identifier); it != externalReferences.end()) + if (auto const* declaration = dynamic_cast(it->second.declaration)) { solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), ""); m_currentNode->variableOccurrences.emplace_back( @@ -565,8 +565,8 @@ void ControlFlowBuilder::operator()(yul::Assignment const& _assignment) visit(*_assignment.value); auto const& externalReferences = m_inlineAssembly->annotation().externalReferences; for (auto const& variable: _assignment.variableNames) - if (externalReferences.count(&variable)) - if (auto const* declaration = dynamic_cast(externalReferences.at(&variable).declaration)) + if (auto it = externalReferences.find(&variable); it != externalReferences.end()) + if (auto const* declaration = dynamic_cast(it->second.declaration)) { solAssert(nativeLocationOf(variable) == originLocationOf(variable), ""); m_currentNode->variableOccurrences.emplace_back( diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index b59273b18d5d..0caed0c401c9 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -37,6 +37,7 @@ #include #include +#include #include using namespace solidity; @@ -215,7 +216,7 @@ FunctionDefinition const* ContractDefinition::receiveFunction() const std::vector const& ContractDefinition::definedInterfaceEvents() const { return m_interfaceEvents.init([&]{ - std::set eventsSeen; + std::unordered_set eventsSeen; std::vector interfaceEvents; for (ContractDefinition const* contract: annotation().linearizedBaseContracts) @@ -280,7 +281,7 @@ std::vector ContractDefinition::interfaceErrors(bool _re std::vector, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const { return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{ - std::set signaturesSeen; + std::unordered_set signaturesSeen; std::vector, FunctionTypePointer>> interfaceFunctionList; for (ContractDefinition const* contract: annotation().linearizedBaseContracts) diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 82f5ea3dc2de..d19193a3b6a2 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -200,7 +200,7 @@ void CompilerContext::appendYulUtilityFunctions(OptimiserSettings const& _optimi appendInlineAssembly( yul::reindent("{\n" + std::move(code) + "\n}"), {}, - m_externallyUsedYulFunctions, + std::set(m_externallyUsedYulFunctions.begin(), m_externallyUsedYulFunctions.end()), true, _optimiserSettings, yulUtilityFileName() diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 72f61113013a..6972314d39cd 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -383,7 +384,7 @@ class CompilerContext /// Collector for yul functions. MultiUseYulFunctionCollector m_yulFunctionCollector; /// Set of externally used yul functions. - std::set m_externallyUsedYulFunctions; + std::unordered_set m_externallyUsedYulFunctions; /// Generated Yul code used as utility. Source references from the bytecode can point here. /// Produced from @a m_yulFunctionCollector. std::string m_generatedYulUtilityCode; diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp index 306f65121964..8cad1572054e 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp @@ -40,9 +40,8 @@ std::string MultiUseYulFunctionCollector::requestedFunctions() std::string MultiUseYulFunctionCollector::createFunction(std::string const& _name, std::function const& _creator) { - if (!m_requestedFunctions.count(_name)) + if (m_requestedFunctions.insert(_name).second) { - m_requestedFunctions.insert(_name); std::string fun = _creator(); solAssert(!fun.empty(), ""); solAssert(fun.find("function " + _name + "(") != std::string::npos, "Function not properly named."); @@ -57,9 +56,8 @@ std::string MultiUseYulFunctionCollector::createFunction( ) { solAssert(!_name.empty(), ""); - if (!m_requestedFunctions.count(_name)) + if (m_requestedFunctions.insert(_name).second) { - m_requestedFunctions.insert(_name); std::vector arguments; std::vector returnParameters; std::string body = _creator(arguments, returnParameters); diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.h b/libsolidity/codegen/MultiUseYulFunctionCollector.h index 050b5858f215..d1d627fd1fac 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.h +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include namespace solidity::frontend { @@ -57,7 +57,7 @@ class MultiUseYulFunctionCollector bool contains(std::string const& _name) const { return m_requestedFunctions.count(_name) > 0; } private: - std::set m_requestedFunctions; + std::unordered_set m_requestedFunctions; std::string m_code; }; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d5cb27b6e1df..d1142a270974 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -73,8 +73,8 @@ struct CopyTranslate: public yul::ASTCopier { // The operator() function is only called in lvalue context. In rvalue context, // only translate(yul::Identifier) is called. - if (m_references.count(&_identifier)) - return translateReference(_identifier); + if (auto it = m_references.find(&_identifier); it != m_references.end()) + return translateReference(_identifier, it->second); else return ASTCopier::operator()(_identifier); } @@ -90,10 +90,11 @@ struct CopyTranslate: public yul::ASTCopier yul::Identifier translate(yul::Identifier const& _identifier) override { - if (!m_references.count(&_identifier)) + auto it = m_references.find(&_identifier); + if (it == m_references.end()) return ASTCopier::translate(_identifier); - yul::Expression translated = translateReference(_identifier); + yul::Expression translated = translateReference(_identifier, it->second); solAssert(std::holds_alternative(translated)); return std::get(std::move(translated)); } @@ -103,9 +104,8 @@ struct CopyTranslate: public yul::ASTCopier /// Translates a reference to a local variable, potentially including /// a suffix. Might return a literal, which causes this to be invalid in /// lvalue-context. - yul::Expression translateReference(yul::Identifier const& _identifier) + yul::Expression translateReference(yul::Identifier const& _identifier, InlineAssemblyAnnotation::ExternalIdentifierInfo const& reference) { - auto const& reference = m_references.at(&_identifier); auto const varDecl = dynamic_cast(reference.declaration); solUnimplementedAssert(varDecl); std::string const& suffix = reference.suffix; diff --git a/libsolidity/experimental/ast/TypeSystem.h b/libsolidity/experimental/ast/TypeSystem.h index c3aa5001a16d..79abe917938f 100644 --- a/libsolidity/experimental/ast/TypeSystem.h +++ b/libsolidity/experimental/ast/TypeSystem.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -186,7 +187,7 @@ class TypeSystem size_t m_numTypeVariables = 0; std::map m_primitiveTypeConstructors; std::map m_primitiveTypeClasses; - std::set m_canonicalTypeNames; + std::unordered_set m_canonicalTypeNames; std::vector m_typeConstructors; std::vector m_typeClasses; TypeEnvironment m_globalTypeEnvironment{*this}; diff --git a/libsolutil/Whiskers.cpp b/libsolutil/Whiskers.cpp index 1f026d9464a7..158ff5a4a937 100644 --- a/libsolutil/Whiskers.cpp +++ b/libsolutil/Whiskers.cpp @@ -172,24 +172,26 @@ std::string Whiskers::replace( std::string conditionName(_match[4]); if (!tagName.empty()) { + auto it = _parameters.find(tagName); assertThrow( - _parameters.count(tagName), + it != _parameters.end(), WhiskersError, "Value for tag " + tagName + " not provided.\n" + "Template:\n" + _template ); - return _parameters.at(tagName); + return it->second; } else if (!listName.empty()) { std::string templ(_match[3]); + auto it = _listParameters.find(listName); assertThrow( - _listParameters.count(listName), + it != _listParameters.end(), WhiskersError, "List parameter " + listName + " not set." ); std::string replacement; - for (auto const& parameters: _listParameters.at(listName)) + for (auto const& parameters: it->second) replacement += replace(templ, joinMaps(_parameters, parameters), _conditions); return replacement; } @@ -201,20 +203,21 @@ std::string Whiskers::replace( { std::string tag = conditionName.substr(1); - if (_parameters.count(tag)) - conditionValue = !_parameters.at(tag).empty(); - else if (_listParameters.count(tag)) - conditionValue = !_listParameters.at(tag).empty(); + if (auto it = _parameters.find(tag); it != _parameters.end()) + conditionValue = !it->second.empty(); + else if (auto it2 = _listParameters.find(tag); it2 != _listParameters.end()) + conditionValue = !it2->second.empty(); else assertThrow(false, WhiskersError, "Tag " + tag + " used as condition but was not set."); } else { + auto it = _conditions.find(conditionName); assertThrow( - _conditions.count(conditionName), + it != _conditions.end(), WhiskersError, "Condition parameter " + conditionName + " not set." ); - conditionValue = _conditions.at(conditionName); + conditionValue = it->second; } return replace( conditionValue ? _match[5] : _match[7], diff --git a/libyul/ASTForward.h b/libyul/ASTForward.h index 868fc84b2827..a7a706487308 100644 --- a/libyul/ASTForward.h +++ b/libyul/ASTForward.h @@ -23,14 +23,13 @@ #pragma once +#include + #include namespace solidity::yul { -class YulString; -using YulName = YulString; - enum class LiteralKind; class LiteralValue; struct Literal; @@ -50,7 +49,6 @@ struct Leave; struct ExpressionStatement; struct Block; struct BuiltinName; -struct BuiltinHandle; class AST; struct NameWithDebugData; diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 79d8bfd26860..0921a9e4cc5e 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -715,8 +715,9 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable) Scope& AsmAnalyzer::scope(Block const* _block) { - yulAssert(m_info.scopes.count(_block) == 1, "Scope requested but not present."); - auto scopePtr = m_info.scopes.at(_block); + auto it = m_info.scopes.find(_block); + yulAssert(it != m_info.scopes.end(), "Scope requested but not present."); + auto scopePtr = it->second; yulAssert(scopePtr, "Scope requested but not present."); return *scopePtr; } diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index 51b8cde2ba1f..35c866c88400 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -36,6 +36,7 @@ #include #include #include +#include #include namespace solidity::langutil @@ -132,7 +133,7 @@ class AsmAnalyzer Scope* m_currentScope = nullptr; /// Variables that are active at the current point in assembly (as opposed to /// "part of the scope but not yet declared") - std::set m_activeVariables; + std::unordered_set m_activeVariables; AsmAnalysisInfo& m_info; langutil::ErrorReporter& m_errorReporter; langutil::EVMVersion m_evmVersion; diff --git a/libyul/Builtins.h b/libyul/Builtins.h index 8ee17de4b668..e5e63ca5c110 100644 --- a/libyul/Builtins.h +++ b/libyul/Builtins.h @@ -18,7 +18,11 @@ #pragma once +#include + #include +#include +#include namespace solidity::yul { @@ -33,3 +37,25 @@ struct BuiltinHandle }; } + +namespace std +{ +template<> struct hash +{ + size_t operator()(solidity::yul::BuiltinHandle const& _handle) const + { + return std::hash{}(_handle.id); + } +}; + +template<> struct hash> +{ + size_t operator()(std::variant const& _handle) const + { + return std::visit( + [](auto const& _v) { return std::hash>{}(_v); }, + _handle + ); + } +}; +} diff --git a/libyul/ControlFlowSideEffectsCollector.cpp b/libyul/ControlFlowSideEffectsCollector.cpp index 3c42972852ba..555741cdd030 100644 --- a/libyul/ControlFlowSideEffectsCollector.cpp +++ b/libyul/ControlFlowSideEffectsCollector.cpp @@ -222,17 +222,17 @@ ControlFlowSideEffectsCollector::ControlFlowSideEffectsCollector( if (calledSideEffects.canRevert) functionSideEffects.canRevert = true; - if (m_functionReferences.count(call)) - _recurse(*m_functionReferences.at(call), _recurse); + if (auto it = m_functionReferences.find(call); it != m_functionReferences.end()) + _recurse(*it->second, _recurse); } }; _visit(*function, _visit); } } -std::map ControlFlowSideEffectsCollector::functionSideEffectsNamed() const +std::unordered_map ControlFlowSideEffectsCollector::functionSideEffectsNamed() const { - std::map result; + std::unordered_map result; for (auto&& [function, sideEffects]: m_functionSideEffects) yulAssert(result.insert({function->name, sideEffects}).second); return result; diff --git a/libyul/ControlFlowSideEffectsCollector.h b/libyul/ControlFlowSideEffectsCollector.h index 6228db2e4946..1dc3f9f7f82c 100644 --- a/libyul/ControlFlowSideEffectsCollector.h +++ b/libyul/ControlFlowSideEffectsCollector.h @@ -101,7 +101,7 @@ class ControlFlowSideEffectsCollector return m_functionSideEffects; } /// Returns the side effects by function name, requires unique function names. - std::map functionSideEffectsNamed() const; + std::unordered_map functionSideEffectsNamed() const; private: /// @returns false if nothing could be processed. diff --git a/libyul/Object.cpp b/libyul/Object.cpp index b2fb582ae5a4..2aee62db3751 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -131,8 +131,8 @@ Object::Structure Object::summarizeStructure() const structure.objectPaths = name.empty() || util::contains(name, '.') ? - std::set{} : - std::set{name}; + std::unordered_set{} : + std::unordered_set{name}; structure.objectName = name; diff --git a/libyul/Object.h b/libyul/Object.h index a816db11b820..97c581e0c0d4 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -35,6 +35,8 @@ #include #include #include +#include +#include namespace solidity::yul { @@ -108,9 +110,9 @@ class Object: public ObjectNode /// The name of the object std::string objectName; /// Available dot-separated paths to nested objects (relative to current object). - std::set objectPaths; + std::unordered_set objectPaths; /// Available dot-separated paths to nested data entries (relative to current object). - std::set dataPaths; + std::unordered_set dataPaths; /// Checks if a path is available. bool contains(std::string const& _path) const { return containsObject(_path) || containsData(_path); } @@ -147,7 +149,7 @@ class Object: public ObjectNode evmasm::SubAssemblyID subId{}; std::vector> subObjects; - std::map> subIndexByName; + std::unordered_map subIndexByName; std::shared_ptr analysisInfo; std::shared_ptr debugData; diff --git a/libyul/ObjectOptimizer.cpp b/libyul/ObjectOptimizer.cpp index e0a0ddb24a3e..08909260309a 100644 --- a/libyul/ObjectOptimizer.cpp +++ b/libyul/ObjectOptimizer.cpp @@ -100,8 +100,9 @@ void ObjectOptimizer::storeOptimizedObject(util::h256 _cacheKey, Object const& _ void ObjectOptimizer::overwriteWithOptimizedObject(util::h256 _cacheKey, Object& _object) const { - yulAssert(m_cachedObjects.count(_cacheKey) != 0); - CachedObject const& cachedObject = m_cachedObjects.at(_cacheKey); + auto it = m_cachedObjects.find(_cacheKey); + yulAssert(it != m_cachedObjects.end()); + CachedObject const& cachedObject = it->second; yulAssert(cachedObject.optimizedAST); yulAssert(cachedObject.dialect); diff --git a/libyul/Scope.cpp b/libyul/Scope.cpp index a73b2f9fd07e..281d69da39ec 100644 --- a/libyul/Scope.cpp +++ b/libyul/Scope.cpp @@ -31,7 +31,7 @@ bool Scope::registerVariable(YulName _name) return false; Variable variable; variable.name = _name; - identifiers[_name] = variable; + identifiers.try_emplace(_name, variable); return true; } @@ -39,7 +39,7 @@ bool Scope::registerFunction(YulName _name, size_t _numArguments, size_t _numRet { if (exists(_name)) return false; - identifiers[_name] = Function{_numArguments, _numReturns, _name}; + identifiers.try_emplace(_name, Function{_numArguments, _numReturns, _name}); return true; } diff --git a/libyul/backends/evm/ConstantOptimiser.cpp b/libyul/backends/evm/ConstantOptimiser.cpp index aa744415bf9d..62daf4d47465 100644 --- a/libyul/backends/evm/ConstantOptimiser.cpp +++ b/libyul/backends/evm/ConstantOptimiser.cpp @@ -122,8 +122,8 @@ Expression const* RepresentationFinder::tryFindRepresentation(u256 const& _value Representation const& RepresentationFinder::findRepresentation(u256 const& _value) { - if (m_cache.count(_value)) - return m_cache.at(_value); + if (auto it = m_cache.find(_value); it != m_cache.end()) + return it->second; yulAssert(m_dialect.auxiliaryBuiltinHandles().not_); yulAssert(m_dialect.auxiliaryBuiltinHandles().exp); diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index 614503e183ac..22d2b663d189 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -490,8 +490,9 @@ void ControlFlowGraphBuilder::operator()(Leave const& leave_) void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) { yulAssert(m_scope, ""); - yulAssert(m_scope->identifiers.count(_function.name), ""); - Scope::Function& function = std::get(m_scope->identifiers.at(_function.name)); + auto it = m_scope->identifiers.find(_function.name); + yulAssert(it != m_scope->identifiers.end(), ""); + Scope::Function& function = std::get(it->second); m_graph.functions.emplace_back(&function); CFG::FunctionInfo& functionInfo = m_graph.functionInfo.at(&function); @@ -507,8 +508,9 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) void ControlFlowGraphBuilder::registerFunction(FunctionDefinition const& _functionDefinition) { yulAssert(m_scope, ""); - yulAssert(m_scope->identifiers.count(_functionDefinition.name), ""); - Scope::Function& function = std::get(m_scope->identifiers.at(_functionDefinition.name)); + auto it = m_scope->identifiers.find(_functionDefinition.name); + yulAssert(it != m_scope->identifiers.end(), ""); + Scope::Function& function = std::get(it->second); yulAssert(m_info.scopes.at(&_functionDefinition.body), ""); Scope* virtualFunctionScope = m_info.scopes.at(m_info.virtualBlocks.at(&_functionDefinition).get()).get(); diff --git a/libyul/backends/evm/EVMBuiltins.cpp b/libyul/backends/evm/EVMBuiltins.cpp index bc459063242b..ae679b2cbfb1 100644 --- a/libyul/backends/evm/EVMBuiltins.cpp +++ b/libyul/backends/evm/EVMBuiltins.cpp @@ -135,10 +135,11 @@ BuiltinFunctionForEVM datasizeBuiltin() _assembly.appendAssemblySize(); else { + auto it = _context.subIDs.find(dataName.str()); std::vector subIdPath = - _context.subIDs.count(dataName.str()) == 0 ? + it == _context.subIDs.end() ? _context.currentObject->pathToSubObject(dataName.str()) : - std::vector{_context.subIDs.at(dataName.str())}; + std::vector{it->second}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataSize(subIdPath); } @@ -161,10 +162,11 @@ BuiltinFunctionForEVM dataoffsetBuiltin() _assembly.appendConstant(0); else { + auto it = _context.subIDs.find(dataName.str()); std::vector subIdPath = - _context.subIDs.count(dataName.str()) == 0 ? + it == _context.subIDs.end() ? _context.currentObject->pathToSubObject(dataName.str()) : - std::vector{_context.subIDs.at(dataName.str())}; + std::vector{it->second}; yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); _assembly.appendDataOffset(subIdPath); } diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 83ec96ddcd2b..da782ed6e169 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -126,8 +126,9 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop) void CodeTransform::deleteVariable(Scope::Variable const& _var) { yulAssert(m_allowStackOpt, ""); - yulAssert(m_context->variableStackHeights.count(&_var) > 0, ""); - m_unusedStackSlots.insert(static_cast(m_context->variableStackHeights[&_var])); + auto it = m_context->variableStackHeights.find(&_var); + yulAssert(it != m_context->variableStackHeights.end(), ""); + m_unusedStackSlots.insert(static_cast(it->second)); m_context->variableStackHeights.erase(&_var); m_context->variableReferences.erase(&_var); m_variablesScheduledForDeletion.erase(&_var); @@ -361,8 +362,9 @@ void CodeTransform::operator()(Switch const& _switch) void CodeTransform::operator()(FunctionDefinition const& _function) { yulAssert(m_scope, ""); - yulAssert(m_scope->identifiers.count(_function.name), ""); - Scope::Function& function = std::get(m_scope->identifiers.at(_function.name)); + auto it = m_scope->identifiers.find(_function.name); + yulAssert(it != m_scope->identifiers.end(), ""); + Scope::Function& function = std::get(it->second); size_t height = 1; yulAssert(m_info.scopes.at(&_function.body), ""); @@ -615,8 +617,9 @@ void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function) AbstractAssembly::LabelID CodeTransform::functionEntryID(Scope::Function const& _scopeFunction) const { - yulAssert(m_context->functionEntryIDs.count(&_scopeFunction), ""); - return m_context->functionEntryIDs.at(&_scopeFunction); + auto it = m_context->functionEntryIDs.find(&_scopeFunction); + yulAssert(it != m_context->functionEntryIDs.end(), ""); + return it->second; } void CodeTransform::visitExpression(Expression const& _expression) @@ -670,7 +673,7 @@ bool statementNeedsReturnVariableSetup(Statement const& _statement, std::vector< std::holds_alternative(_statement) ) { - std::map references = VariableReferencesCounter::countReferences(_statement); + std::unordered_map references = VariableReferencesCounter::countReferences(_statement); auto isReferenced = [&references](NameWithDebugData const& _returnVariable) { return references.count(_returnVariable.name); }; @@ -776,8 +779,9 @@ void CodeTransform::generateAssignment(Identifier const& _variableName) size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulName _varName, bool _forSwap) { - yulAssert(m_context->variableStackHeights.count(&_var), ""); - size_t heightDiff = static_cast(m_assembly.stackHeight()) - m_context->variableStackHeights[&_var]; + auto it = m_context->variableStackHeights.find(&_var); + yulAssert(it != m_context->variableStackHeights.end(), ""); + size_t heightDiff = static_cast(m_assembly.stackHeight()) - it->second; yulAssert(heightDiff > (_forSwap ? 1 : 0), "Negative stack difference for variable."); size_t limit = m_dialect.reachableStackDepth() + (_forSwap ? 1 : 0); if (heightDiff > limit) diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index c0bbac81b35e..f3504008035b 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -29,6 +29,7 @@ #include #include +#include namespace solidity::langutil { @@ -198,7 +199,7 @@ class CodeTransform BuiltinContext& m_builtinContext; bool const m_allowStackOpt = true; UseNamedLabels const m_useNamedLabelsForFunctions = UseNamedLabels::Never; - std::set m_assignedNamedLabels; + std::unordered_set m_assignedNamedLabels; ExternalIdentifierAccess::CodeGenerator m_identifierAccessCodeGen; std::shared_ptr m_context; diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 62f0d7a695c3..7ca36564d98e 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -87,7 +87,7 @@ bool isLowLevelControlFlowInstruction(evmasm::Instruction const& _instruction) } } -std::set> createReservedIdentifiers(langutil::EVMVersion _evmVersion, std::optional _eofVersion) +EVMDialect::ReservedIdentifiers createReservedIdentifiers(langutil::EVMVersion _evmVersion, std::optional _eofVersion) { // TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name // basefee for VMs before london. @@ -149,7 +149,7 @@ std::set> createReservedIdentifiers(langutil::EVMVersio !langutil::EVMVersion::firstWithEOF().hasOpcode(_instr, std::nullopt); }; - std::set> reserved; + EVMDialect::ReservedIdentifiers reserved; for (auto const& instr: evmasm::c_instructions) { std::string name = toLower(instr.first); @@ -165,19 +165,17 @@ std::set> createReservedIdentifiers(langutil::EVMVersio ) reserved.emplace(name); } - reserved += std::vector{ + reserved.insert({ "linkersymbol", "datasize", "dataoffset", "datacopy", "setimmutable", "loadimmutable", - }; + }); if (_eofVersion.has_value()) - reserved += std::vector{ - "auxdataloadn", - }; + reserved.insert({"auxdataloadn"}); return reserved; } diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index fa92b1cf3242..7a1a39eb5e7a 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace solidity::yul @@ -109,13 +110,22 @@ class EVMDialect: public Dialect static EVMBuiltins const& allBuiltins(); +public: + struct StringHashTransparent + { + using is_transparent = void; + size_t operator()(std::string_view _s) const { return std::hash{}(_s); } + }; + using ReservedIdentifiers = std::unordered_set>; + +protected: bool const m_objectAccess; langutil::EVMVersion const m_evmVersion; std::optional m_eofVersion; std::unordered_map m_builtinFunctionsByName; std::vector m_functions; std::array, verbatimIDOffset> mutable m_verbatimFunctions{}; - std::set> m_reserved; + ReservedIdentifiers m_reserved; std::optional m_discardFunction; std::optional m_equalityFunction; diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp index 69cd046debd0..6bcd3c324832 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -354,10 +354,11 @@ void OptimizedEVMCodeTransform::createStackLayout(langutil::DebugData::ConstPtr }, [&](FunctionCallReturnLabelSlot const& _returnLabel) { - if (!m_returnLabels.count(&_returnLabel.call.get())) - m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId(); + auto [it, inserted] = m_returnLabels.try_emplace(&_returnLabel.call.get()); + if (inserted) + it->second = m_assembly.newLabelId(); m_assembly.setSourceLocation(originLocationOf(_returnLabel.call.get())); - m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get())); + m_assembly.appendLabelReference(it->second); m_assembly.setSourceLocation(sourceLocation); }, [&](VariableSlot const& _variable) @@ -482,12 +483,13 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) else { // Generate a jump label for the target, if not already present. - if (!m_blockLabels.count(_jump.target)) - m_blockLabels[_jump.target] = m_assembly.newLabelId(); + auto [it, inserted] = m_blockLabels.try_emplace(_jump.target); + if (inserted) + it->second = m_assembly.newLabelId(); // If we already have generated the target block, jump to it, otherwise generate it in place. if (m_generated.count(_jump.target)) - m_assembly.appendJumpTo(m_blockLabels[_jump.target]); + m_assembly.appendJumpTo(it->second); else (*this)(*_jump.target); } @@ -498,10 +500,10 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) createStackLayout(debugDataOf(_conditionalJump), blockInfo.exitLayout); // Create labels for the targets, if not already present. - if (!m_blockLabels.count(_conditionalJump.nonZero)) - m_blockLabels[_conditionalJump.nonZero] = m_assembly.newLabelId(); - if (!m_blockLabels.count(_conditionalJump.zero)) - m_blockLabels[_conditionalJump.zero] = m_assembly.newLabelId(); + if (auto [it, inserted] = m_blockLabels.try_emplace(_conditionalJump.nonZero); inserted) + it->second = m_assembly.newLabelId(); + if (auto [it, inserted] = m_blockLabels.try_emplace(_conditionalJump.zero); inserted) + it->second = m_assembly.newLabelId(); // Assert that we have the correct condition on stack. yulAssert(!m_stack.empty(), ""); diff --git a/libyul/backends/evm/ssa/CodeTransform.cpp b/libyul/backends/evm/ssa/CodeTransform.cpp index caca86153f8b..a9665cd5fb43 100644 --- a/libyul/backends/evm/ssa/CodeTransform.cpp +++ b/libyul/backends/evm/ssa/CodeTransform.cpp @@ -29,6 +29,8 @@ #include #include +#include + using namespace solidity::yul; using namespace solidity::yul::ssa; @@ -80,7 +82,7 @@ CodeTransform::FunctionLabels CodeTransform::registerFunctionLabels( AbstractAssembly& _assembly, ControlFlow const& _controlFlow) { FunctionLabels functionLabels; - std::set assignedFunctionNames; + std::unordered_set assignedFunctionNames; for (auto const& [_function, _functionGraph]: _controlFlow.functionGraphMapping) { diff --git a/libyul/backends/evm/ssa/SSACFGBuilder.cpp b/libyul/backends/evm/ssa/SSACFGBuilder.cpp index 7b5f8e004cfd..731ea239b6a1 100644 --- a/libyul/backends/evm/ssa/SSACFGBuilder.cpp +++ b/libyul/backends/evm/ssa/SSACFGBuilder.cpp @@ -380,8 +380,9 @@ void SSACFGBuilder::operator()(Leave const& _leaveStatement) void SSACFGBuilder::registerFunctionDefinition(FunctionDefinition const& _functionDefinition) { yulAssert(m_scope, ""); - yulAssert(m_scope->identifiers.count(_functionDefinition.name), ""); - auto& function = std::get(m_scope->identifiers.at(_functionDefinition.name)); + auto it = m_scope->identifiers.find(_functionDefinition.name); + yulAssert(it != m_scope->identifiers.end(), ""); + auto& function = std::get(it->second); m_graph.functions.emplace_back(function); m_functionDefinitions.emplace_back(&function, &_functionDefinition); } diff --git a/libyul/optimiser/ASTCopier.h b/libyul/optimiser/ASTCopier.h index e1c3a16aa3ea..ff09d12916c8 100644 --- a/libyul/optimiser/ASTCopier.h +++ b/libyul/optimiser/ASTCopier.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace solidity::yul { @@ -125,7 +126,7 @@ class FunctionCopier: public ASTCopier { public: FunctionCopier( - std::map const& _translations + std::unordered_map const& _translations ): m_translations(_translations) {} @@ -134,7 +135,7 @@ class FunctionCopier: public ASTCopier private: /// A mapping between old and new names. We replace the names of variable declarations contained /// in the mapping with their new names. - std::map const& m_translations; + std::unordered_map const& m_translations; }; } diff --git a/libyul/optimiser/BlockHasher.cpp b/libyul/optimiser/BlockHasher.cpp index 6e8e8ed62f57..749e1ae81e6e 100644 --- a/libyul/optimiser/BlockHasher.cpp +++ b/libyul/optimiser/BlockHasher.cpp @@ -130,11 +130,11 @@ void BlockHasher::operator()(VariableDeclaration const& _varDecl) hash64(_varDecl.variables.size()); for (auto const& var: _varDecl.variables) { - yulAssert(!m_variableReferences.count(var.name), ""); - m_variableReferences[var.name] = VariableReference{ + auto [it, inserted] = m_variableReferences.try_emplace(var.name, VariableReference{ m_internalIdentifierCount++, false - }; + }); + yulAssert(inserted, ""); } ASTWalker::operator()(_varDecl); } diff --git a/libyul/optimiser/CallGraphGenerator.cpp b/libyul/optimiser/CallGraphGenerator.cpp index 9b69835dc4f1..b816b33460b6 100644 --- a/libyul/optimiser/CallGraphGenerator.cpp +++ b/libyul/optimiser/CallGraphGenerator.cpp @@ -53,8 +53,8 @@ struct CallGraphCycleFinder else { currentPath.emplace_back(_function); - if (callGraph.functionCalls.count(_function)) - for (auto const& child: callGraph.functionCalls.at(_function)) + if (auto it = callGraph.functionCalls.find(_function); it != callGraph.functionCalls.end()) + for (auto const& child: it->second) visit(child); currentPath.pop_back(); visited.insert(_function); @@ -101,8 +101,8 @@ void CallGraphGenerator::operator()(FunctionDefinition const& _functionDefinitio { YulName previousFunction = m_currentFunction; m_currentFunction = _functionDefinition.name; - yulAssert(m_callGraph.functionCalls.count(m_currentFunction) == 0, ""); - m_callGraph.functionCalls[m_currentFunction] = {}; + auto [it, inserted] = m_callGraph.functionCalls.try_emplace(m_currentFunction); + yulAssert(inserted, ""); ASTWalker::operator()(_functionDefinition); m_currentFunction = previousFunction; } diff --git a/libyul/optimiser/CircularReferencesPruner.cpp b/libyul/optimiser/CircularReferencesPruner.cpp index d238f8da2148..28c8ea401cdd 100644 --- a/libyul/optimiser/CircularReferencesPruner.cpp +++ b/libyul/optimiser/CircularReferencesPruner.cpp @@ -55,8 +55,8 @@ std::set CircularReferencesPruner::functionsCalledFromOutermostContext( return util::BreadthFirstSearch{{verticesToTraverse.begin(), verticesToTraverse.end()}}.run( [&_callGraph](YulName _function, auto&& _addChild) { - if (_callGraph.functionCalls.count(_function)) - for (auto const& callee: _callGraph.functionCalls.at(_function)) + if (auto it = _callGraph.functionCalls.find(_function); it != _callGraph.functionCalls.end()) + for (auto const& callee: it->second) if (std::holds_alternative(callee) && _callGraph.functionCalls.count(std::get(callee))) _addChild(std::get(callee)); }).visited; diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index 1a6f3911a1bb..7ee64f286cab 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -46,7 +46,7 @@ void CommonSubexpressionEliminator::run(OptimiserStepContext& _context, Block& _ CommonSubexpressionEliminator::CommonSubexpressionEliminator( Dialect const& _dialect, - std::map _functionSideEffects + std::unordered_map _functionSideEffects ): DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects)) { diff --git a/libyul/optimiser/CommonSubexpressionEliminator.h b/libyul/optimiser/CommonSubexpressionEliminator.h index 713c35f0229c..6babaf1e791d 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.h +++ b/libyul/optimiser/CommonSubexpressionEliminator.h @@ -53,7 +53,7 @@ class CommonSubexpressionEliminator: public DataFlowAnalyzer private: CommonSubexpressionEliminator( Dialect const& _dialect, - std::map _functionSideEffects + std::unordered_map _functionSideEffects ); protected: diff --git a/libyul/optimiser/ConditionalSimplifier.h b/libyul/optimiser/ConditionalSimplifier.h index c78052126f5f..c8982b5fa808 100644 --- a/libyul/optimiser/ConditionalSimplifier.h +++ b/libyul/optimiser/ConditionalSimplifier.h @@ -23,6 +23,8 @@ #include #include +#include + namespace solidity::yul { @@ -62,12 +64,12 @@ class ConditionalSimplifier: public ASTModifier private: explicit ConditionalSimplifier( Dialect const& _dialect, - std::map _sideEffects + std::unordered_map _sideEffects ): m_dialect(_dialect), m_functionSideEffects(std::move(_sideEffects)) {} Dialect const& m_dialect; - std::map m_functionSideEffects; + std::unordered_map m_functionSideEffects; }; } diff --git a/libyul/optimiser/ConditionalUnsimplifier.h b/libyul/optimiser/ConditionalUnsimplifier.h index dc1c6e24544e..450b389bc642 100644 --- a/libyul/optimiser/ConditionalUnsimplifier.h +++ b/libyul/optimiser/ConditionalUnsimplifier.h @@ -22,6 +22,8 @@ #include #include +#include + namespace solidity::yul { @@ -42,12 +44,12 @@ class ConditionalUnsimplifier: public ASTModifier private: explicit ConditionalUnsimplifier( Dialect const& _dialect, - std::map const& _sideEffects + std::unordered_map const& _sideEffects ): m_dialect(_dialect), m_functionSideEffects(_sideEffects) {} Dialect const& m_dialect; - std::map const& m_functionSideEffects; + std::unordered_map const& m_functionSideEffects; }; } diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 1aecd6bd4a91..69661761a986 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -44,7 +44,7 @@ using namespace solidity::yul; DataFlowAnalyzer::DataFlowAnalyzer( Dialect const& _dialect, MemoryAndStorage _analyzeStores, - std::map _functionSideEffects + std::unordered_map _functionSideEffects ): m_dialect(_dialect), m_functionSideEffects(std::move(_functionSideEffects)), @@ -107,7 +107,7 @@ void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl) std::set names; for (auto const& var: _varDecl.variables) names.emplace(var.name); - m_variableScopes.back().variables += names; + m_variableScopes.back().variables.insert(names.begin(), names.end()); if (_varDecl.value) { diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index 7b731a4eb877..6d4dea9474aa 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -32,8 +32,12 @@ #include #include +#include + #include #include +#include +#include namespace solidity::yul { @@ -89,7 +93,7 @@ class DataFlowAnalyzer: public ASTModifier explicit DataFlowAnalyzer( Dialect const& _dialect, MemoryAndStorage _analyzeStores, - std::map _functionSideEffects = {} + std::unordered_map _functionSideEffects = {} ); using ASTModifier::operator(); @@ -105,7 +109,7 @@ class DataFlowAnalyzer: public ASTModifier /// @returns the current value of the given variable, if known - always movable. AssignedValue const* variableValue(YulName _variable) const { return util::valueOrNullptr(m_state.value, _variable); } std::vector const* sortedReferences(YulName _variable) const { return util::valueOrNullptr(m_state.sortedReferences, _variable); } - std::map const& allValues() const { return m_state.value; } + std::unordered_map const& allValues() const { return m_state.value; } std::optional storageValue(YulName _key) const; std::optional memoryValue(YulName _key) const; std::optional keccakValue(YulName _start, YulName _length) const; @@ -165,20 +169,29 @@ class DataFlowAnalyzer: public ASTModifier Dialect const& m_dialect; /// Side-effects of user-defined functions. Worst-case side-effects are assumed /// if this is not provided or the function is not found. - std::map m_functionSideEffects; + std::unordered_map m_functionSideEffects; private: + struct YulNamePairHash + { + size_t operator()(std::pair const& _pair) const + { + size_t seed = std::hash{}(_pair.first); + boost::hash_combine(seed, std::hash{}(_pair.second)); + return seed; + } + }; struct Environment { std::unordered_map storage; std::unordered_map memory; /// If keccak[s, l] = y then y := keccak256(s, l) occurs in the code. - std::map, YulName> keccak; + std::unordered_map, YulName, YulNamePairHash> keccak; }; struct State { /// Current values of variables, always movable. - std::map value; + std::unordered_map value; /// m_references[a].contains(b) <=> the current expression assigned to a references b /// The mapped vectors _must always_ be sorted std::unordered_map> sortedReferences; @@ -213,7 +226,7 @@ class DataFlowAnalyzer: public ASTModifier struct Scope { explicit Scope(bool _isFunction): isFunction(_isFunction) {} - std::set variables; + std::unordered_set variables; bool isFunction; }; /// Special expression whose address will be used in m_value. diff --git a/libyul/optimiser/DeadCodeEliminator.h b/libyul/optimiser/DeadCodeEliminator.h index 701af3ad1561..e612c9f94f90 100644 --- a/libyul/optimiser/DeadCodeEliminator.h +++ b/libyul/optimiser/DeadCodeEliminator.h @@ -27,6 +27,7 @@ #include #include +#include namespace solidity::yul { @@ -62,11 +63,11 @@ class DeadCodeEliminator: public ASTModifier private: DeadCodeEliminator( Dialect const& _dialect, - std::map _sideEffects + std::unordered_map _sideEffects ): m_dialect(_dialect), m_functionSideEffects(std::move(_sideEffects)) {} Dialect const& m_dialect; - std::map m_functionSideEffects; + std::unordered_map m_functionSideEffects; }; } diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h index 7ff186f0a8c7..a8a21d86f954 100644 --- a/libyul/optimiser/Disambiguator.h +++ b/libyul/optimiser/Disambiguator.h @@ -28,6 +28,7 @@ #include #include +#include namespace solidity::yul { @@ -66,7 +67,7 @@ class Disambiguator: public ASTCopier std::set const& m_externallyUsedIdentifiers; std::vector m_scopes; - std::map m_translations; + std::unordered_map m_translations; NameDispenser m_nameDispenser; }; diff --git a/libyul/optimiser/EqualStoreEliminator.h b/libyul/optimiser/EqualStoreEliminator.h index 87f8cae161a6..874a815d1378 100644 --- a/libyul/optimiser/EqualStoreEliminator.h +++ b/libyul/optimiser/EqualStoreEliminator.h @@ -45,7 +45,7 @@ class EqualStoreEliminator: public DataFlowAnalyzer private: EqualStoreEliminator( Dialect const& _dialect, - std::map _functionSideEffects + std::unordered_map _functionSideEffects ): DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)) {} diff --git a/libyul/optimiser/EquivalentFunctionCombiner.h b/libyul/optimiser/EquivalentFunctionCombiner.h index 627dcb3ff4fd..70d4a1ceb17c 100644 --- a/libyul/optimiser/EquivalentFunctionCombiner.h +++ b/libyul/optimiser/EquivalentFunctionCombiner.h @@ -25,6 +25,8 @@ #include #include +#include + namespace solidity::yul { @@ -46,8 +48,8 @@ class EquivalentFunctionCombiner: public ASTModifier void operator()(FunctionCall& _funCall) override; private: - EquivalentFunctionCombiner(std::map _duplicates): m_duplicates(std::move(_duplicates)) {} - std::map m_duplicates; + EquivalentFunctionCombiner(std::unordered_map _duplicates): m_duplicates(std::move(_duplicates)) {} + std::unordered_map m_duplicates; }; diff --git a/libyul/optimiser/EquivalentFunctionDetector.h b/libyul/optimiser/EquivalentFunctionDetector.h index 7cd161af1a45..6548586e9f00 100644 --- a/libyul/optimiser/EquivalentFunctionDetector.h +++ b/libyul/optimiser/EquivalentFunctionDetector.h @@ -24,6 +24,8 @@ #include #include +#include + namespace solidity::yul { @@ -35,7 +37,7 @@ namespace solidity::yul class EquivalentFunctionDetector: public ASTWalker { public: - static std::map run(Block& _block) + static std::unordered_map run(Block& _block) { EquivalentFunctionDetector detector{BlockHasher::run(_block)}; detector(_block); @@ -49,8 +51,8 @@ class EquivalentFunctionDetector: public ASTWalker EquivalentFunctionDetector(std::map _blockHashes): m_blockHashes(std::move(_blockHashes)) {} std::map m_blockHashes; - std::map> m_candidates; - std::map m_duplicates; + std::unordered_map> m_candidates; + std::unordered_map m_duplicates; }; diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp index 0d59dab2d2e7..472bc421a63c 100644 --- a/libyul/optimiser/ExpressionInliner.cpp +++ b/libyul/optimiser/ExpressionInliner.cpp @@ -54,11 +54,12 @@ void ExpressionInliner::visit(Expression& _expression) { FunctionCall& funCall = std::get(_expression); YulString const functionName{resolveFunctionName(funCall.functionName, m_dialect)}; - if (!m_inlinableFunctions.count(functionName)) + auto it = m_inlinableFunctions.find(functionName); + if (it == m_inlinableFunctions.end()) return; - FunctionDefinition const& fun = *m_inlinableFunctions.at(functionName); + FunctionDefinition const& fun = *it->second; - std::map substitutions; + std::unordered_map substitutions; for (size_t i = 0; i < funCall.arguments.size(); i++) { Expression const& arg = funCall.arguments[i]; diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h index 07f86ddce73a..9e4ac9a84d13 100644 --- a/libyul/optimiser/ExpressionJoiner.h +++ b/libyul/optimiser/ExpressionJoiner.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace solidity::yul { @@ -93,7 +93,7 @@ class ExpressionJoiner: public ASTModifier private: Block* m_currentBlock = nullptr; ///< Pointer to current block holding the statement being visited. size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement. - std::map m_references; ///< Holds reference counts to all variable declarations in current block. + std::unordered_map m_references; ///< Holds reference counts to all variable declarations in current block. }; } diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 894ada60962e..e2422cc5302c 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -67,7 +67,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& // Store size of global statements. m_functionSizes[YulName{}] = CodeSize::codeSize(_ast); - std::map references = ReferencesCounter::countReferences(m_ast); + std::unordered_map references = ReferencesCounter::countReferences(m_ast); for (auto& statement: m_ast.statements) { if (!std::holds_alternative(statement)) @@ -258,7 +258,7 @@ void FullInliner::handleBlock(YulName _currentFunctionName, Block& _block) bool FullInliner::recursive(FunctionDefinition const& _fun) const { - std::map references = ReferencesCounter::countReferences(_fun); + std::unordered_map references = ReferencesCounter::countReferences(_fun); return references[_fun.name] > 0; } diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 4620194a4e51..da613e756a2d 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -32,6 +32,7 @@ #include #include +#include #include namespace solidity::yul @@ -110,15 +111,15 @@ class FullInliner: public ASTModifier Block& m_ast; std::map m_functions; /// Functions not to be inlined (because they contain the ``leave`` statement). - std::set m_noInlineFunctions; + std::unordered_set m_noInlineFunctions; /// True, if the code contains a ``memoryguard`` and we can expect to be able to move variables to memory later. bool m_hasMemoryGuard = false; /// Set of recursive functions. std::set m_recursiveFunctions; /// Names of functions to always inline. - std::set m_singleUse; + std::unordered_set m_singleUse; /// Variables that are constants (used for inlining heuristic) - std::set m_constants; + std::unordered_set m_constants; std::map m_functionSizes; NameDispenser& m_nameDispenser; Dialect const& m_dialect; diff --git a/libyul/optimiser/FunctionSpecializer.cpp b/libyul/optimiser/FunctionSpecializer.cpp index cbbf14e8f84a..378d5145f2fe 100644 --- a/libyul/optimiser/FunctionSpecializer.cpp +++ b/libyul/optimiser/FunctionSpecializer.cpp @@ -87,13 +87,13 @@ FunctionDefinition FunctionSpecializer::specialize( { yulAssert(_arguments.size() == _f.parameters.size(), ""); - std::map translatedNames = applyMap( + std::unordered_map translatedNames = applyMap( NameCollector{_f, NameCollector::OnlyVariables}.names(), [&](auto& _name) -> std::pair { return std::make_pair(_name, m_nameDispenser.newName(_name)); }, - std::map{} + std::unordered_map{} ); FunctionDefinition newFunction = std::get(FunctionCopier{translatedNames}(_f)); @@ -140,10 +140,10 @@ void FunctionSpecializer::run(OptimiserStepContext& _context, Block& _ast) { auto& functionDefinition = std::get(_s); - if (f.m_oldToNewMap.count(functionDefinition.name)) + if (auto it = f.m_oldToNewMap.find(functionDefinition.name); it != f.m_oldToNewMap.end()) { std::vector out = applyMap( - f.m_oldToNewMap.at(functionDefinition.name), + it->second, [&](auto& _p) -> Statement { return f.specialize(functionDefinition, std::move(_p.first), std::move(_p.second)); diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp index 6061fa3e9725..5bc82d80066a 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp @@ -56,7 +56,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu // would not be valid here if we were searching inside a functionally inlinable // function body. assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, ""); - m_disallowedIdentifiers = std::set{retVariable, _function.name}; + m_disallowedIdentifiers = std::unordered_set{retVariable, _function.name}; std::visit(*this, *assignment.value); if (!m_foundDisallowedIdentifier) m_inlinableFunctions[_function.name] = &_function; diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.h b/libyul/optimiser/InlinableExpressionFunctionFinder.h index c6897c173529..3b97f8629add 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.h +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace solidity::yul { @@ -56,7 +56,7 @@ class InlinableExpressionFunctionFinder: public ASTWalker void checkAllowed(FunctionName const& _name); bool m_foundDisallowedIdentifier = false; - std::set m_disallowedIdentifiers; + std::unordered_set m_disallowedIdentifiers; std::map m_inlinableFunctions; }; diff --git a/libyul/optimiser/KnowledgeBase.cpp b/libyul/optimiser/KnowledgeBase.cpp index ceaa8f06b359..cc994cab14b4 100644 --- a/libyul/optimiser/KnowledgeBase.cpp +++ b/libyul/optimiser/KnowledgeBase.cpp @@ -32,7 +32,7 @@ using namespace solidity; using namespace solidity::yul; -KnowledgeBase::KnowledgeBase(std::map const& _ssaValues, Dialect const& _dialect): +KnowledgeBase::KnowledgeBase(std::unordered_map const& _ssaValues, Dialect const& _dialect): m_valuesAreSSA(true), m_variableValues([_ssaValues](YulName _var) { return util::valueOrNullptr(_ssaValues, _var); }), m_addBuiltinHandle(_dialect.findBuiltin("add")), diff --git a/libyul/optimiser/KnowledgeBase.h b/libyul/optimiser/KnowledgeBase.h index 0852f8902592..3a05467574c0 100644 --- a/libyul/optimiser/KnowledgeBase.h +++ b/libyul/optimiser/KnowledgeBase.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include namespace solidity::yul @@ -69,7 +71,7 @@ class KnowledgeBase m_subBuiltinHandle(_dialect.findBuiltin("sub")) {} /// Constructor to use if source code is in SSA form and values are constant. - explicit KnowledgeBase(std::map const& _ssaValues, Dialect const& _dialect); + explicit KnowledgeBase(std::unordered_map const& _ssaValues, Dialect const& _dialect); bool knownToBeDifferent(YulName _a, YulName _b); std::optional differenceIfKnownConstant(YulName _a, YulName _b); @@ -123,10 +125,12 @@ class KnowledgeBase /// Offsets for each variable to one representative per group. /// The empty string is the representative of the constant value zero. - std::map m_offsets; + std::unordered_map m_offsets; /// Last known value of each variable we queried. - std::map m_lastKnownValue; + std::unordered_map m_lastKnownValue; /// For each representative, variables that use it to offset from. + /// NOTE: Must be std::map with std::set inner container because + /// reset() picks a new representative via `*group->begin()` (deterministic minimum). std::map> m_groupMembers; }; diff --git a/libyul/optimiser/LoadResolver.h b/libyul/optimiser/LoadResolver.h index d878076929a6..0d93f77f63a9 100644 --- a/libyul/optimiser/LoadResolver.h +++ b/libyul/optimiser/LoadResolver.h @@ -49,7 +49,7 @@ class LoadResolver: public DataFlowAnalyzer private: LoadResolver( Dialect const& _dialect, - std::map _functionSideEffects, + std::unordered_map _functionSideEffects, bool _containsMSize, std::optional _expectedExecutionsPerDeployment ): diff --git a/libyul/optimiser/LoopInvariantCodeMotion.cpp b/libyul/optimiser/LoopInvariantCodeMotion.cpp index f2e7d040802e..c5402ed77bd4 100644 --- a/libyul/optimiser/LoopInvariantCodeMotion.cpp +++ b/libyul/optimiser/LoopInvariantCodeMotion.cpp @@ -32,10 +32,10 @@ using namespace solidity::yul; void LoopInvariantCodeMotion::run(OptimiserStepContext& _context, Block& _ast) { - std::map functionSideEffects = + std::unordered_map functionSideEffects = SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast)); bool containsMSize = MSizeFinder::containsMSize(_context.dialect, _ast); - std::set ssaVars = SSAValueTracker::ssaVariables(_ast); + std::unordered_set ssaVars = SSAValueTracker::ssaVariables(_ast); LoopInvariantCodeMotion{_context.dialect, ssaVars, functionSideEffects, containsMSize}(_ast); } @@ -56,7 +56,7 @@ void LoopInvariantCodeMotion::operator()(Block& _block) bool LoopInvariantCodeMotion::canBePromoted( VariableDeclaration const& _varDecl, - std::set const& _varsDefinedInCurrentScope, + std::unordered_set const& _varsDefinedInCurrentScope, SideEffects const& _forLoopSideEffects ) const { @@ -90,7 +90,7 @@ std::optional> LoopInvariantCodeMotion::rewriteLoop(ForLo std::vector replacement; for (Block* block: {&_for.post, &_for.body}) { - std::set varsDefinedInScope; + std::unordered_set varsDefinedInScope; util::iterateReplacing( block->statements, [&](Statement& _s) -> std::optional> diff --git a/libyul/optimiser/LoopInvariantCodeMotion.h b/libyul/optimiser/LoopInvariantCodeMotion.h index d03a91eeeba9..6e1e1684c3c6 100644 --- a/libyul/optimiser/LoopInvariantCodeMotion.h +++ b/libyul/optimiser/LoopInvariantCodeMotion.h @@ -21,6 +21,9 @@ #include #include +#include +#include + namespace solidity::yul { @@ -48,8 +51,8 @@ class LoopInvariantCodeMotion: public ASTModifier private: explicit LoopInvariantCodeMotion( Dialect const& _dialect, - std::set const& _ssaVariables, - std::map const& _functionSideEffects, + std::unordered_set const& _ssaVariables, + std::unordered_map const& _functionSideEffects, bool _containsMSize ): m_containsMSize(_containsMSize), @@ -61,15 +64,15 @@ class LoopInvariantCodeMotion: public ASTModifier /// @returns true if the given variable declaration can be moved to in front of the loop. bool canBePromoted( VariableDeclaration const& _varDecl, - std::set const& _varsDefinedInCurrentScope, + std::unordered_set const& _varsDefinedInCurrentScope, SideEffects const& _forLoopSideEffects ) const; std::optional> rewriteLoop(ForLoop& _for); bool m_containsMSize = true; Dialect const& m_dialect; - std::set const& m_ssaVariables; - std::map const& m_functionSideEffects; + std::unordered_set const& m_ssaVariables; + std::unordered_map const& m_functionSideEffects; }; } diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index cdcc28822d94..82c4b7192100 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -24,6 +24,8 @@ #include #include +#include + namespace solidity::yul { @@ -141,7 +143,7 @@ class AssignmentCounter: public ASTWalker void operator()(Assignment const& _assignment) override; std::size_t assignmentCount(YulName _name) const; private: - std::map m_assignmentCounters; + std::unordered_map m_assignmentCounters; }; } diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp index cde9b64f67d1..912e4f66048b 100644 --- a/libyul/optimiser/NameCollector.cpp +++ b/libyul/optimiser/NameCollector.cpp @@ -60,21 +60,21 @@ void ReferencesCounter::operator()(FunctionCall const& _funCall) ASTWalker::operator()(_funCall); } -std::map ReferencesCounter::countReferences(Block const& _block) +std::unordered_map ReferencesCounter::countReferences(Block const& _block) { ReferencesCounter counter; counter(_block); return std::move(counter.m_references); } -std::map ReferencesCounter::countReferences(FunctionDefinition const& _function) +std::unordered_map ReferencesCounter::countReferences(FunctionDefinition const& _function) { ReferencesCounter counter; counter(_function); return std::move(counter.m_references); } -std::map ReferencesCounter::countReferences(Expression const& _expression) +std::unordered_map ReferencesCounter::countReferences(Expression const& _expression) { ReferencesCounter counter; counter.visit(_expression); @@ -86,28 +86,28 @@ void VariableReferencesCounter::operator()(Identifier const& _identifier) ++m_references[_identifier.name]; } -std::map VariableReferencesCounter::countReferences(Block const& _block) +std::unordered_map VariableReferencesCounter::countReferences(Block const& _block) { VariableReferencesCounter counter; counter(_block); return std::move(counter.m_references); } -std::map VariableReferencesCounter::countReferences(FunctionDefinition const& _function) +std::unordered_map VariableReferencesCounter::countReferences(FunctionDefinition const& _function) { VariableReferencesCounter counter; counter(_function); return std::move(counter.m_references); } -std::map VariableReferencesCounter::countReferences(Expression const& _expression) +std::unordered_map VariableReferencesCounter::countReferences(Expression const& _expression) { VariableReferencesCounter counter; counter.visit(_expression); return std::move(counter.m_references); } -std::map VariableReferencesCounter::countReferences(Statement const& _statement) +std::unordered_map VariableReferencesCounter::countReferences(Statement const& _statement) { VariableReferencesCounter counter; counter.visit(_statement); diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h index 2adc73ced8e3..caf214cb58be 100644 --- a/libyul/optimiser/NameCollector.h +++ b/libyul/optimiser/NameCollector.h @@ -22,10 +22,12 @@ #pragma once #include +#include #include #include #include +#include namespace solidity::yul { @@ -76,12 +78,12 @@ class ReferencesCounter: public ASTWalker void operator()(Identifier const& _identifier) override; void operator()(FunctionCall const& _funCall) override; - static std::map countReferences(Block const& _block); - static std::map countReferences(FunctionDefinition const& _function); - static std::map countReferences(Expression const& _expression); + static std::unordered_map countReferences(Block const& _block); + static std::unordered_map countReferences(FunctionDefinition const& _function); + static std::unordered_map countReferences(Expression const& _expression); private: - std::map m_references; + std::unordered_map m_references; }; /** @@ -93,13 +95,13 @@ class VariableReferencesCounter: public ASTWalker using ASTWalker::operator (); void operator()(Identifier const& _identifier) override; - static std::map countReferences(Block const& _block); - static std::map countReferences(FunctionDefinition const& _function); - static std::map countReferences(Expression const& _expression); - static std::map countReferences(Statement const& _statement); + static std::unordered_map countReferences(Block const& _block); + static std::unordered_map countReferences(FunctionDefinition const& _function); + static std::unordered_map countReferences(Expression const& _expression); + static std::unordered_map countReferences(Statement const& _statement); private: - std::map m_references; + std::unordered_map m_references; }; /** diff --git a/libyul/optimiser/NameDisplacer.cpp b/libyul/optimiser/NameDisplacer.cpp index 7430c26c3046..1ba72aef5c02 100644 --- a/libyul/optimiser/NameDisplacer.cpp +++ b/libyul/optimiser/NameDisplacer.cpp @@ -79,7 +79,7 @@ void NameDisplacer::checkAndReplaceNew(YulName& _name) void NameDisplacer::checkAndReplace(YulName& _name) const { - if (m_translations.count(_name)) - _name = m_translations.at(_name); + if (auto it = m_translations.find(_name); it != m_translations.end()) + _name = it->second; } diff --git a/libyul/optimiser/NameSimplifier.cpp b/libyul/optimiser/NameSimplifier.cpp index 0572a9003523..732ab2726c1b 100644 --- a/libyul/optimiser/NameSimplifier.cpp +++ b/libyul/optimiser/NameSimplifier.cpp @@ -77,7 +77,7 @@ void NameSimplifier::operator()(FunctionCall& _funCall) void NameSimplifier::findSimplification(YulName const& _name) { - if (m_translations.count(_name)) + if (m_translations.contains(_name)) return; std::string name = _name.str(); diff --git a/libyul/optimiser/NameSimplifier.h b/libyul/optimiser/NameSimplifier.h index f3426d60f8f8..97cecbfddda4 100644 --- a/libyul/optimiser/NameSimplifier.h +++ b/libyul/optimiser/NameSimplifier.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace solidity::yul { @@ -66,7 +67,7 @@ class NameSimplifier: public ASTModifier void translate(YulName& _name); OptimiserStepContext& m_context; - std::map m_translations; + std::unordered_map m_translations; }; } diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index 1d3535fdae82..fd820bd26cc4 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -44,7 +44,7 @@ Rematerialiser::Rematerialiser( ): DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore), m_referenceCounts(VariableReferencesCounter::countReferences(_ast)), - m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)), + m_varsToAlwaysRematerialize(_varsToAlwaysRematerialize.begin(), _varsToAlwaysRematerialize.end()), m_onlySelectedVariables(_onlySelectedVariables) { } diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index a482ef53e015..2c506fcc950f 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -24,6 +24,9 @@ #include #include +#include +#include + namespace solidity::yul { @@ -67,8 +70,8 @@ class Rematerialiser: public DataFlowAnalyzer using ASTModifier::visit; void visit(Expression& _e) override; - std::map m_referenceCounts; - std::set m_varsToAlwaysRematerialize; + std::unordered_map m_referenceCounts; + std::unordered_set m_varsToAlwaysRematerialize; bool m_onlySelectedVariables = false; }; diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp index 1d5270f8f497..d9c7411a314f 100644 --- a/libyul/optimiser/SSATransform.cpp +++ b/libyul/optimiser/SSATransform.cpp @@ -290,8 +290,8 @@ class PropagateValues: public ASTModifier void PropagateValues::operator()(Identifier& _identifier) { - if (m_currentVariableValues.count(_identifier.name)) - _identifier.name = m_currentVariableValues[_identifier.name]; + if (auto it = m_currentVariableValues.find(_identifier.name); it != m_currentVariableValues.end()) + _identifier.name = it->second; } void PropagateValues::operator()(VariableDeclaration& _varDecl) diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index d39ce4b8d263..2431c8fb6519 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -49,11 +49,11 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) setValue(_varDecl.variables.front().name, _varDecl.value.get()); } -std::set SSAValueTracker::ssaVariables(Block const& _ast) +std::unordered_set SSAValueTracker::ssaVariables(Block const& _ast) { SSAValueTracker t; t(_ast); - std::set ssaVars; + std::unordered_set ssaVars; for (auto const& value: t.values()) ssaVars.insert(value.first); return ssaVars; @@ -61,12 +61,12 @@ std::set SSAValueTracker::ssaVariables(Block const& _ast) void SSAValueTracker::setValue(YulName _name, Expression const* _value) { + if (!_value) + _value = &m_zero; + auto [it, inserted] = m_values.emplace(_name, _value); assertThrow( - m_values.count(_name) == 0, + inserted, OptimizerException, "Source needs to be disambiguated." ); - if (!_value) - _value = &m_zero; - m_values[_name] = _value; } diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index 2448f99a84c4..74b46b27e8e9 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -27,6 +27,7 @@ #include #include +#include namespace solidity::yul { @@ -50,7 +51,7 @@ class SSAValueTracker: public ASTWalker std::map const& values() const { return m_values; } Expression const* value(YulName _name) const { return m_values.at(_name); } - static std::set ssaVariables(Block const& _ast); + static std::unordered_set ssaVariables(Block const& _ast); private: void setValue(YulName _name, Expression const* _value); diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index a505126ae9f1..bc43c19be469 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -33,6 +33,7 @@ #include #include +#include using namespace solidity; using namespace solidity::yul; @@ -41,7 +42,7 @@ using namespace solidity::yul; SideEffectsCollector::SideEffectsCollector( Dialect const& _dialect, Expression const& _expression, - std::map const* _functionSideEffects + std::unordered_map const* _functionSideEffects ): SideEffectsCollector(_dialect, _functionSideEffects) { @@ -57,7 +58,7 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co SideEffectsCollector::SideEffectsCollector( Dialect const& _dialect, Block const& _ast, - std::map const* _functionSideEffects + std::unordered_map const* _functionSideEffects ): SideEffectsCollector(_dialect, _functionSideEffects) { @@ -67,7 +68,7 @@ SideEffectsCollector::SideEffectsCollector( SideEffectsCollector::SideEffectsCollector( Dialect const& _dialect, ForLoop const& _ast, - std::map const* _functionSideEffects + std::unordered_map const* _functionSideEffects ): SideEffectsCollector(_dialect, _functionSideEffects) { @@ -81,8 +82,13 @@ void SideEffectsCollector::operator()(FunctionCall const& _functionCall) FunctionHandle functionHandle = functionNameToHandle(_functionCall.functionName); if (BuiltinFunction const* builtin = resolveBuiltinFunction(_functionCall.functionName, m_dialect)) m_sideEffects += builtin->sideEffects; - else if (m_functionSideEffects && m_functionSideEffects->count(functionHandle)) - m_sideEffects += m_functionSideEffects->at(functionHandle); + else if (m_functionSideEffects) + { + if (auto it = m_functionSideEffects->find(functionHandle); it != m_functionSideEffects->end()) + m_sideEffects += it->second; + else + m_sideEffects += SideEffects::worst(); + } else m_sideEffects += SideEffects::worst(); } @@ -117,7 +123,7 @@ void MSizeFinder::operator()(FunctionCall const& _functionCall) m_msizeFound = true; } -std::map SideEffectsPropagator::sideEffects( +std::unordered_map SideEffectsPropagator::sideEffects( Dialect const& _dialect, CallGraph const& _directCallGraph ) @@ -128,7 +134,7 @@ std::map SideEffectsPropagator::sideEffects( // In the future, we should refine that, because the property // is actually a bit different from "not movable". - std::map ret; + std::unordered_map ret; for (auto const& function: _directCallGraph.functionsWithLoops) { ret[function].movable = false; @@ -149,7 +155,7 @@ std::map SideEffectsPropagator::sideEffects( { FunctionHandle funName = call.first; SideEffects sideEffects; - auto _visit = [&, visited = std::set{}](FunctionHandle _function, auto&& _recurse) mutable { + auto _visit = [&, visited = std::unordered_set{}](FunctionHandle _function, auto&& _recurse) mutable { if (!visited.insert(_function).second) return; if (sideEffects == SideEffects::worst()) @@ -158,8 +164,8 @@ std::map SideEffectsPropagator::sideEffects( sideEffects += _dialect.builtin(*builtinHandle).sideEffects; else { - if (ret.count(_function)) - sideEffects += ret[_function]; + if (auto it = ret.find(_function); it != ret.end()) + sideEffects += it->second; for (FunctionHandle const& callee: _directCallGraph.functionCalls.at(_function)) _recurse(callee, _recurse); } @@ -242,8 +248,9 @@ bool TerminationFinder::containsNonContinuingFunctionCall(Expression const& _exp yulAssert(std::holds_alternative(functionCall->functionName)); auto const& name = std::get(functionCall->functionName).name; - if (m_functionSideEffects && m_functionSideEffects->count(name)) - return !m_functionSideEffects->at(name).canContinue; + if (m_functionSideEffects) + if (auto it = m_functionSideEffects->find(name); it != m_functionSideEffects->end()) + return !it->second.canContinue; } return false; } diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h index 9d3c724af2d7..7d455743b878 100644 --- a/libyul/optimiser/Semantics.h +++ b/libyul/optimiser/Semantics.h @@ -22,12 +22,14 @@ #pragma once #include +#include #include #include #include #include #include +#include namespace solidity::yul { @@ -42,23 +44,23 @@ class SideEffectsCollector: public ASTWalker public: explicit SideEffectsCollector( Dialect const& _dialect, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {} SideEffectsCollector( Dialect const& _dialect, Expression const& _expression, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ); SideEffectsCollector(Dialect const& _dialect, Statement const& _statement); SideEffectsCollector( Dialect const& _dialect, Block const& _ast, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ); SideEffectsCollector( Dialect const& _dialect, ForLoop const& _ast, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ); using ASTWalker::operator(); @@ -117,7 +119,7 @@ class SideEffectsCollector: public ASTWalker private: Dialect const& m_dialect; - std::map const* m_functionSideEffects = nullptr; + std::unordered_map const* m_functionSideEffects = nullptr; SideEffects m_sideEffects; }; @@ -130,7 +132,7 @@ class SideEffectsCollector: public ASTWalker class SideEffectsPropagator { public: - static std::map sideEffects( + static std::unordered_map sideEffects( Dialect const& _dialect, CallGraph const& _directCallGraph ); @@ -195,7 +197,7 @@ class MovableChecker: public SideEffectsCollector public: explicit MovableChecker( Dialect const& _dialect, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ): SideEffectsCollector(_dialect, _functionSideEffects) {} MovableChecker(Dialect const& _dialect, Expression const& _expression); @@ -231,7 +233,7 @@ class TerminationFinder TerminationFinder( Dialect const& _dialect, - std::map const* _functionSideEffects = nullptr + std::unordered_map const* _functionSideEffects = nullptr ): m_dialect(_dialect), m_functionSideEffects(_functionSideEffects) {} /// @returns the index of the first statement in the provided sequence @@ -256,7 +258,7 @@ class TerminationFinder private: Dialect const& m_dialect; - std::map const* m_functionSideEffects; + std::unordered_map const* m_functionSideEffects; }; } diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index b0be60d63442..f832cb9a66cd 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -92,9 +92,9 @@ class RematCandidateSelector: public DataFlowAnalyzer YulName varName = _varDecl.variables.front().name; if (AssignedValue const* value = variableValue(varName)) { - yulAssert(!m_expressionCodeCost.count(varName), ""); m_candidates.emplace_back(m_currentFunctionName, varName); - m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *value->value); + auto [it, inserted] = m_expressionCodeCost.try_emplace(varName, CodeCost::codeCost(m_dialect, *value->value)); + yulAssert(inserted, ""); } } } diff --git a/libyul/optimiser/StackLimitEvader.cpp b/libyul/optimiser/StackLimitEvader.cpp index 91a9eb84fe8c..226d2d4506b2 100644 --- a/libyul/optimiser/StackLimitEvader.cpp +++ b/libyul/optimiser/StackLimitEvader.cpp @@ -91,8 +91,9 @@ struct MemoryOffsetAllocator for (YulName variable: *unreachables) // The empty case is a function with too many arguments or return values, // which was already handled above. - if (!variable.empty() && !slotAllocations.count(variable)) - slotAllocations[variable] = requiredSlots++; + if (!variable.empty()) + if (auto [it, inserted] = slotAllocations.try_emplace(variable); inserted) + it->second = requiredSlots++; } return slotsRequiredForFunction[_function] = requiredSlots; diff --git a/libyul/optimiser/StackToMemoryMover.cpp b/libyul/optimiser/StackToMemoryMover.cpp index 15df64b3f252..07cbf007475c 100644 --- a/libyul/optimiser/StackToMemoryMover.cpp +++ b/libyul/optimiser/StackToMemoryMover.cpp @@ -313,9 +313,9 @@ void StackToMemoryMover::visit(Expression& _expression) std::optional StackToMemoryMover::VariableMemoryOffsetTracker::operator()(YulName const& _variable) const { - if (m_memorySlots.count(_variable)) + if (auto it = m_memorySlots.find(_variable); it != m_memorySlots.end()) { - uint64_t slot = m_memorySlots.at(_variable); + uint64_t slot = it->second; yulAssert(slot < m_numRequiredSlots, ""); auto const memoryOffset = m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1); return valueOfNumberLiteral(toCompactHexWithPrefix(memoryOffset)); diff --git a/libyul/optimiser/Substitution.cpp b/libyul/optimiser/Substitution.cpp index 5baec51e34a6..5ae21d673f45 100644 --- a/libyul/optimiser/Substitution.cpp +++ b/libyul/optimiser/Substitution.cpp @@ -31,9 +31,9 @@ Expression Substitution::translate(Expression const& _expression) if (std::holds_alternative(_expression)) { YulName name = std::get(_expression).name; - if (m_substitutions.count(name)) + if (auto it = m_substitutions.find(name); it != m_substitutions.end()) // No recursive substitution - return ASTCopier().translate(*m_substitutions.at(name)); + return ASTCopier().translate(*it->second); } return ASTCopier::translate(_expression); } diff --git a/libyul/optimiser/Substitution.h b/libyul/optimiser/Substitution.h index 2d4ccffc0148..e431c98e8e72 100644 --- a/libyul/optimiser/Substitution.h +++ b/libyul/optimiser/Substitution.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace solidity::yul { @@ -35,13 +35,13 @@ namespace solidity::yul class Substitution: public ASTCopier { public: - Substitution(std::map const& _substitutions): + Substitution(std::unordered_map const& _substitutions): m_substitutions(_substitutions) {} Expression translate(Expression const& _expression) override; private: - std::map const& m_substitutions; + std::unordered_map const& m_substitutions; }; } diff --git a/libyul/optimiser/SyntacticalEquality.h b/libyul/optimiser/SyntacticalEquality.h index 0db52c9690df..6722d7ffde24 100644 --- a/libyul/optimiser/SyntacticalEquality.h +++ b/libyul/optimiser/SyntacticalEquality.h @@ -26,6 +26,7 @@ #include #include +#include namespace solidity::yul { @@ -85,8 +86,8 @@ class SyntacticallyEqual } std::size_t m_idsUsed = 0; - std::map m_identifiersLHS; - std::map m_identifiersRHS; + std::unordered_map m_identifiersLHS; + std::unordered_map m_identifiersRHS; }; /** diff --git a/libyul/optimiser/UnusedAssignEliminator.h b/libyul/optimiser/UnusedAssignEliminator.h index 73628c929671..54c98af2b89e 100644 --- a/libyul/optimiser/UnusedAssignEliminator.h +++ b/libyul/optimiser/UnusedAssignEliminator.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include namespace solidity::yul @@ -121,7 +123,7 @@ class UnusedAssignEliminator: public UnusedStoreBase explicit UnusedAssignEliminator( Dialect const& _dialect, - std::map _controlFlowSideEffects + std::unordered_map _controlFlowSideEffects ): UnusedStoreBase(_dialect), m_controlFlowSideEffects(_controlFlowSideEffects) @@ -143,8 +145,8 @@ class UnusedAssignEliminator: public UnusedStoreBase void markUsed(YulName _variable); - std::set m_returnVariables; - std::map m_controlFlowSideEffects; + std::unordered_set m_returnVariables; + std::unordered_map m_controlFlowSideEffects; }; } diff --git a/libyul/optimiser/UnusedFunctionParameterPruner.cpp b/libyul/optimiser/UnusedFunctionParameterPruner.cpp index 49c0a9c4d427..fd073d2e132d 100644 --- a/libyul/optimiser/UnusedFunctionParameterPruner.cpp +++ b/libyul/optimiser/UnusedFunctionParameterPruner.cpp @@ -42,7 +42,7 @@ using namespace solidity::yul::unusedFunctionsCommon; void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ast) { - std::map references = VariableReferencesCounter::countReferences(_ast); + std::unordered_map references = VariableReferencesCounter::countReferences(_ast); auto used = [&](auto v) -> bool { return references.count(v.name); }; // Function name and a pair of boolean masks, the first corresponds to parameters and the second @@ -95,11 +95,11 @@ void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ { // The original function except that it has a new name (e.g., `f_1`) FunctionDefinition& originalFunction = std::get(_s); - if (newToOriginalNames.count(originalFunction.name)) + if (auto it = newToOriginalNames.find(originalFunction.name); it != newToOriginalNames.end()) { YulName linkingFunctionName = originalFunction.name; - YulName originalFunctionName = newToOriginalNames.at(linkingFunctionName); + YulName originalFunctionName = it->second; std::pair, std::vector> used = usedParametersAndReturnVariables.at(originalFunctionName); diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 2f982b164093..8dd8096878af 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -43,7 +43,7 @@ UnusedPruner::UnusedPruner( Dialect const& _dialect, Block& _ast, bool _allowMSizeOptimization, - std::map const* _functionSideEffects, + std::unordered_map const* _functionSideEffects, std::set const& _externallyUsedFunctions ): m_dialect(_dialect), @@ -122,7 +122,7 @@ void UnusedPruner::runUntilStabilised( Dialect const& _dialect, Block& _ast, bool _allowMSizeOptimization, - std::map const* _functionSideEffects, + std::unordered_map const* _functionSideEffects, std::set const& _externallyUsedFunctions ) { @@ -147,7 +147,7 @@ void UnusedPruner::runUntilStabilisedOnFullAST( std::set const& _externallyUsedFunctions ) { - std::map functionSideEffects = + std::unordered_map functionSideEffects = SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)); bool allowMSizeOptimization = !MSizeFinder::containsMSize(_dialect, _ast); runUntilStabilised(_dialect, _ast, allowMSizeOptimization, &functionSideEffects, _externallyUsedFunctions); @@ -155,16 +155,18 @@ void UnusedPruner::runUntilStabilisedOnFullAST( bool UnusedPruner::used(YulName _name) const { - return m_references.count(_name) && m_references.at(_name) > 0; + auto it = m_references.find(_name); + return it != m_references.end() && it->second > 0; } -void UnusedPruner::subtractReferences(std::map const& _subtrahend) +void UnusedPruner::subtractReferences(std::unordered_map const& _subtrahend) { for (auto const& ref: _subtrahend) { - assertThrow(m_references.count(ref.first), OptimizerException, ""); - assertThrow(m_references.at(ref.first) >= ref.second, OptimizerException, ""); - m_references[ref.first] -= ref.second; + auto it = m_references.find(ref.first); + assertThrow(it != m_references.end(), OptimizerException, ""); + assertThrow(it->second >= ref.second, OptimizerException, ""); + it->second -= ref.second; m_shouldRunAgain = true; } } diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h index cd9a7e341d7f..91d6a59cbf0b 100644 --- a/libyul/optimiser/UnusedPruner.h +++ b/libyul/optimiser/UnusedPruner.h @@ -27,6 +27,7 @@ #include #include +#include namespace solidity::yul { @@ -63,7 +64,7 @@ class UnusedPruner: public ASTModifier Dialect const& _dialect, Block& _ast, bool _allowMSizeOptimization, - std::map const* _functionSideEffects = nullptr, + std::unordered_map const* _functionSideEffects = nullptr, std::set const& _externallyUsedFunctions = {} ); @@ -82,18 +83,18 @@ class UnusedPruner: public ASTModifier Dialect const& _dialect, Block& _ast, bool _allowMSizeOptimization, - std::map const* _functionSideEffects = nullptr, + std::unordered_map const* _functionSideEffects = nullptr, std::set const& _externallyUsedFunctions = {} ); bool used(YulName _name) const; - void subtractReferences(std::map const& _subtrahend); + void subtractReferences(std::unordered_map const& _subtrahend); Dialect const& m_dialect; bool m_allowMSizeOptimization = false; - std::map const* m_functionSideEffects = nullptr; + std::unordered_map const* m_functionSideEffects = nullptr; bool m_shouldRunAgain = false; - std::map m_references; + std::unordered_map m_references; }; } diff --git a/libyul/optimiser/UnusedStoreEliminator.cpp b/libyul/optimiser/UnusedStoreEliminator.cpp index 6f2f1ee938f8..6b98b8675ccc 100644 --- a/libyul/optimiser/UnusedStoreEliminator.cpp +++ b/libyul/optimiser/UnusedStoreEliminator.cpp @@ -46,14 +46,14 @@ using namespace solidity::yul; void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast) { - std::map functionSideEffects = SideEffectsPropagator::sideEffects( + std::unordered_map functionSideEffects = SideEffectsPropagator::sideEffects( _context.dialect, CallGraphGenerator::callGraph(_ast) ); SSAValueTracker ssaValues; ssaValues(_ast); - std::map values; + std::unordered_map values; for (auto const& [name, expression]: ssaValues.values()) values[name] = AssignedValue{expression, {}}; @@ -82,9 +82,9 @@ void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast) UnusedStoreEliminator::UnusedStoreEliminator( Dialect const& _dialect, - std::map const& _functionSideEffects, - std::map _controlFlowSideEffects, - std::map const& _ssaValues, + std::unordered_map const& _functionSideEffects, + std::unordered_map _controlFlowSideEffects, + std::unordered_map const& _ssaValues, bool _ignoreMemory ): UnusedStoreBase(_dialect), diff --git a/libyul/optimiser/UnusedStoreEliminator.h b/libyul/optimiser/UnusedStoreEliminator.h index 45d363dfc9fc..8b3796f91f73 100644 --- a/libyul/optimiser/UnusedStoreEliminator.h +++ b/libyul/optimiser/UnusedStoreEliminator.h @@ -32,6 +32,7 @@ #include #include +#include #include namespace solidity::yul @@ -62,9 +63,9 @@ class UnusedStoreEliminator: public UnusedStoreBase explicit UnusedStoreEliminator( Dialect const& _dialect, - std::map const& _functionSideEffects, - std::map _controlFlowSideEffects, - std::map const& _ssaValues, + std::unordered_map const& _functionSideEffects, + std::unordered_map _controlFlowSideEffects, + std::unordered_map const& _ssaValues, bool _ignoreMemory ); @@ -122,9 +123,9 @@ class UnusedStoreEliminator: public UnusedStoreBase std::optional identifierNameIfSSA(Expression const& _expression) const; bool const m_ignoreMemory; - std::map const& m_functionSideEffects; - std::map m_controlFlowSideEffects; - std::map const& m_ssaValues; + std::unordered_map const& m_functionSideEffects; + std::unordered_map m_controlFlowSideEffects; + std::unordered_map const& m_ssaValues; std::map m_storeOperations; diff --git a/libyul/optimiser/VarNameCleaner.cpp b/libyul/optimiser/VarNameCleaner.cpp index 8d34ce85e408..59cf1e07202f 100644 --- a/libyul/optimiser/VarNameCleaner.cpp +++ b/libyul/optimiser/VarNameCleaner.cpp @@ -37,7 +37,7 @@ VarNameCleaner::VarNameCleaner( std::set _namesToKeep ): m_dialect{_dialect}, - m_namesToKeep{std::move(_namesToKeep)}, + m_namesToKeep(_namesToKeep.begin(), _namesToKeep.end()), m_translatedNames{} { for (auto const& statement: _ast.statements) @@ -51,9 +51,9 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef) yulAssert(!m_insideFunction, ""); m_insideFunction = true; - std::set globalUsedNames = std::move(m_usedNames); + std::unordered_set globalUsedNames = std::move(m_usedNames); m_usedNames = m_namesToKeep; - std::map globalTranslatedNames; + std::unordered_map globalTranslatedNames; swap(globalTranslatedNames, m_translatedNames); renameVariables(_funDef.parameters); diff --git a/libyul/optimiser/VarNameCleaner.h b/libyul/optimiser/VarNameCleaner.h index 47f3aca48db9..5330e08eb4ef 100644 --- a/libyul/optimiser/VarNameCleaner.h +++ b/libyul/optimiser/VarNameCleaner.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include namespace solidity::yul { @@ -84,13 +86,13 @@ class VarNameCleaner: public ASTModifier Dialect const& m_dialect; /// These names will not be modified. - std::set m_namesToKeep; + std::unordered_set m_namesToKeep; /// Set of names that are in use. - std::set m_usedNames; + std::unordered_set m_usedNames; /// Maps old to new names. - std::map m_translatedNames; + std::unordered_map m_translatedNames; /// Whether the traverse is inside a function definition. /// Used to assert that a function definition cannot be inside another. diff --git a/test/libyul/FunctionSideEffects.cpp b/test/libyul/FunctionSideEffects.cpp index cb24ed764c32..c86b5ecb1bbe 100644 --- a/test/libyul/FunctionSideEffects.cpp +++ b/test/libyul/FunctionSideEffects.cpp @@ -92,7 +92,7 @@ TestCase::TestResult FunctionSideEffects::run(std::ostream& _stream, std::string return TestResult::FatalError; } - std::map functionSideEffects = SideEffectsPropagator::sideEffects( + std::unordered_map functionSideEffects = SideEffectsPropagator::sideEffects( yulStack.dialect(), CallGraphGenerator::callGraph(yulStack.parserResult()->code()->root()) );