diff --git a/libevmcore/AssemblyItem.h b/libevmcore/AssemblyItem.h index 3e222a6eb..7400954d3 100644 --- a/libevmcore/AssemblyItem.h +++ b/libevmcore/AssemblyItem.h @@ -43,9 +43,16 @@ class AssemblyItem public: enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; - AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} - AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} - AssemblyItem(AssemblyItemType _type, u256 _data = 0): m_type(_type), m_data(_data) {} + AssemblyItem(u256 _push, SourceLocation const& _location = SourceLocation()): + AssemblyItem(Push, _push, _location) { } + AssemblyItem(Instruction _i, SourceLocation const& _location = SourceLocation()): + AssemblyItem(Operation, byte(_i), _location) { } + AssemblyItem(AssemblyItemType _type, u256 _data = 0, SourceLocation const& _location = SourceLocation()): + m_type(_type), + m_data(_data), + m_location(_location) + { + } AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, m_data); } AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, m_data); } diff --git a/libevmcore/CommonSubexpressionEliminator.cpp b/libevmcore/CommonSubexpressionEliminator.cpp index d857158b9..65305b42a 100644 --- a/libevmcore/CommonSubexpressionEliminator.cpp +++ b/libevmcore/CommonSubexpressionEliminator.cpp @@ -41,9 +41,9 @@ vector CommonSubexpressionEliminator::getOptimizedItems() if (!m_stackElements.empty()) minHeight = min(minHeight, m_stackElements.begin()->first); for (int height = minHeight; height <= 0; ++height) - initialStackContents[height] = initialStackElement(height); + initialStackContents[height] = initialStackElement(height, SourceLocation()); for (int height = minHeight; height <= m_stackHeight; ++height) - targetStackContents[height] = stackElement(height); + targetStackContents[height] = stackElement(height, SourceLocation()); // Debug info: //stream(cout, initialStackContents, targetStackContents); @@ -111,30 +111,46 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _co if (SemanticInformation::isDupInstruction(_item)) setStackElement( m_stackHeight + 1, - stackElement(m_stackHeight - int(instruction) + int(Instruction::DUP1)) + stackElement( + m_stackHeight - int(instruction) + int(Instruction::DUP1), + _item.getLocation() + ) ); else if (SemanticInformation::isSwapInstruction(_item)) swapStackElements( m_stackHeight, - m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1) + m_stackHeight - 1 - int(instruction) + int(Instruction::SWAP1), + _item.getLocation() ); else if (instruction != Instruction::POP) { vector arguments(info.args); for (int i = 0; i < info.args; ++i) - arguments[i] = stackElement(m_stackHeight - i); + arguments[i] = stackElement(m_stackHeight - i, _item.getLocation()); if (_item.instruction() == Instruction::SSTORE) - storeInStorage(arguments[0], arguments[1]); + storeInStorage(arguments[0], arguments[1], _item.getLocation()); else if (_item.instruction() == Instruction::SLOAD) - setStackElement(m_stackHeight + _item.deposit(), loadFromStorage(arguments[0])); + setStackElement( + m_stackHeight + _item.deposit(), + loadFromStorage(arguments[0], _item.getLocation()) + ); else if (_item.instruction() == Instruction::MSTORE) - storeInMemory(arguments[0], arguments[1]); + storeInMemory(arguments[0], arguments[1], _item.getLocation()); else if (_item.instruction() == Instruction::MLOAD) - setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0])); + setStackElement( + m_stackHeight + _item.deposit(), + loadFromMemory(arguments[0], _item.getLocation()) + ); else if (_item.instruction() == Instruction::SHA3) - setStackElement(m_stackHeight + _item.deposit(), applySha3(arguments.at(0), arguments.at(1))); + setStackElement( + m_stackHeight + _item.deposit(), + applySha3(arguments.at(0), arguments.at(1), _item.getLocation()) + ); else - setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, _copyItem)); + setStackElement( + m_stackHeight + _item.deposit(), + m_expressionClasses.find(_item, arguments, _copyItem) + ); } m_stackHeight += _item.deposit(); } @@ -145,22 +161,27 @@ void CommonSubexpressionEliminator::optimizeBreakingItem() if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI)) return; - static AssemblyItem s_jump = Instruction::JUMP; + SourceLocation const& location = m_breakingItem->getLocation(); + AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - Id condition = stackElement(m_stackHeight - 1); + Id condition = stackElement(m_stackHeight - 1, location); Id zero = m_expressionClasses.find(u256(0)); if (m_expressionClasses.knownToBeDifferent(condition, zero)) { - feedItem(Instruction::SWAP1, true); - feedItem(Instruction::POP, true); - m_breakingItem = &s_jump; + feedItem(AssemblyItem(Instruction::SWAP1, location), true); + feedItem(AssemblyItem(Instruction::POP, location), true); + + AssemblyItem item(Instruction::JUMP, location); + item.setJumpType(jumpType); + m_breakingItem = m_expressionClasses.storeItem(item); return; } Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition}); if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero)) { - feedItem(Instruction::POP, true); - feedItem(Instruction::POP, true); + AssemblyItem it(Instruction::POP, location); + feedItem(it, true); + feedItem(it, true); m_breakingItem = nullptr; } } @@ -170,33 +191,43 @@ void CommonSubexpressionEliminator::setStackElement(int _stackHeight, Id _class) m_stackElements[_stackHeight] = _class; } -void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _stackHeightB) +void CommonSubexpressionEliminator::swapStackElements( + int _stackHeightA, + int _stackHeightB, + SourceLocation const& _location +) { assertThrow(_stackHeightA != _stackHeightB, OptimizerException, "Swap on same stack elements."); // ensure they are created - stackElement(_stackHeightA); - stackElement(_stackHeightB); + stackElement(_stackHeightA, _location); + stackElement(_stackHeightB, _location); swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]); } -ExpressionClasses::Id CommonSubexpressionEliminator::stackElement(int _stackHeight) +ExpressionClasses::Id CommonSubexpressionEliminator::stackElement( + int _stackHeight, + SourceLocation const& _location +) { if (m_stackElements.count(_stackHeight)) return m_stackElements.at(_stackHeight); // Stack element not found (not assigned yet), create new equivalence class. - return m_stackElements[_stackHeight] = initialStackElement(_stackHeight); + return m_stackElements[_stackHeight] = initialStackElement(_stackHeight, _location); } -ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(int _stackHeight) +ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement( + int _stackHeight, + SourceLocation const& _location +) { assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested."); assertThrow(_stackHeight > -16, StackTooDeepException, ""); // This is a special assembly item that refers to elements pre-existing on the initial stack. - return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight))); + return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight), _location)); } -void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value) +void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value, SourceLocation const& _location) { if (m_storageContent.count(_slot) && m_storageContent[_slot] == _value) // do not execute the storage if we know that the value is already there @@ -210,22 +241,25 @@ void CommonSubexpressionEliminator::storeInStorage(Id _slot, Id _value) if (m_expressionClasses.knownToBeDifferent(storageItem.first, _slot) || storageItem.second == _value) storageContents.insert(storageItem); m_storageContent = move(storageContents); - Id id = m_expressionClasses.find(Instruction::SSTORE, {_slot, _value}, true, m_sequenceNumber); + + AssemblyItem item(Instruction::SSTORE, _location); + Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber); m_storeOperations.push_back(StoreOperation(StoreOperation::Storage, _slot, m_sequenceNumber, id)); m_storageContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes m_sequenceNumber++; } -ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(Id _slot) +ExpressionClasses::Id CommonSubexpressionEliminator::loadFromStorage(Id _slot, SourceLocation const& _location) { if (m_storageContent.count(_slot)) return m_storageContent.at(_slot); - else - return m_storageContent[_slot] = m_expressionClasses.find(Instruction::SLOAD, {_slot}, true, m_sequenceNumber); + + AssemblyItem item(Instruction::SLOAD, _location); + return m_storageContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber); } -void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value) +void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value, SourceLocation const& _location) { if (m_memoryContent.count(_slot) && m_memoryContent[_slot] == _value) // do not execute the store if we know that the value is already there @@ -237,34 +271,45 @@ void CommonSubexpressionEliminator::storeInMemory(Id _slot, Id _value) if (m_expressionClasses.knownToBeDifferentBy32(memoryItem.first, _slot)) memoryContents.insert(memoryItem); m_memoryContent = move(memoryContents); - Id id = m_expressionClasses.find(Instruction::MSTORE, {_slot, _value}, true, m_sequenceNumber); + + AssemblyItem item(Instruction::MSTORE, _location); + Id id = m_expressionClasses.find(item, {_slot, _value}, true, m_sequenceNumber); m_storeOperations.push_back(StoreOperation(StoreOperation::Memory, _slot, m_sequenceNumber, id)); m_memoryContent[_slot] = _value; // increment a second time so that we get unique sequence numbers for writes m_sequenceNumber++; } -ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(Id _slot) +ExpressionClasses::Id CommonSubexpressionEliminator::loadFromMemory(Id _slot, SourceLocation const& _location) { if (m_memoryContent.count(_slot)) return m_memoryContent.at(_slot); - else - return m_memoryContent[_slot] = m_expressionClasses.find(Instruction::MLOAD, {_slot}, true, m_sequenceNumber); + + AssemblyItem item(Instruction::MLOAD, _location); + return m_memoryContent[_slot] = m_expressionClasses.find(item, {_slot}, true, m_sequenceNumber); } -CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(Id _start, Id _length) +CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3( + Id _start, + Id _length, + SourceLocation const& _location +) { + AssemblyItem sha3Item(Instruction::SHA3, _location); // Special logic if length is a short constant, otherwise we cannot tell. u256 const* l = m_expressionClasses.knownConstant(_length); // unknown or too large length if (!l || *l > 128) - return m_expressionClasses.find(Instruction::SHA3, {_start, _length}, true, m_sequenceNumber); + return m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber); vector arguments; for (u256 i = 0; i < *l; i += 32) { - Id slot = m_expressionClasses.find(Instruction::ADD, {_start, m_expressionClasses.find(i)}); - arguments.push_back(loadFromMemory(slot)); + Id slot = m_expressionClasses.find( + AssemblyItem(Instruction::ADD, _location), + {_start, m_expressionClasses.find(i)} + ); + arguments.push_back(loadFromMemory(slot, _location)); } if (m_knownSha3Hashes.count(arguments)) return m_knownSha3Hashes.at(arguments); @@ -276,10 +321,10 @@ CommonSubexpressionEliminator::Id CommonSubexpressionEliminator::applySha3(Id _s for (Id a: arguments) data += toBigEndian(*m_expressionClasses.knownConstant(a)); data.resize(size_t(*l)); - v = m_expressionClasses.find(u256(sha3(data))); + v = m_expressionClasses.find(AssemblyItem(u256(sha3(data)), _location)); } else - v = m_expressionClasses.find(Instruction::SHA3, {_start, _length}, true, m_sequenceNumber); + v = m_expressionClasses.find(sha3Item, {_start, _length}, true, m_sequenceNumber); return m_knownSha3Hashes[arguments] = v; } @@ -333,12 +378,13 @@ AssemblyItems CSECodeGenerator::generateCode( assertThrow(position != c_invalidPosition, OptimizerException, ""); if (position == targetItem.first) continue; + SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation(); if (position < targetItem.first) // it is already at its target, we need another copy - appendDup(position); + appendDup(position, location); else - appendOrRemoveSwap(position); - appendOrRemoveSwap(targetItem.first); + appendOrRemoveSwap(position, location); + appendOrRemoveSwap(targetItem.first, location); } // remove surplus elements @@ -404,7 +450,8 @@ void CSECodeGenerator::addDependencies(Id _c) case Instruction::SHA3: { Id length = expr.arguments.at(1); - Id offsetToStart = m_expressionClasses.find(Instruction::SUB, {slot, slotToLoadFrom}); + AssemblyItem offsetInstr(Instruction::SUB, expr.item->getLocation()); + Id offsetToStart = m_expressionClasses.find(offsetInstr, {slot, slotToLoadFrom}); u256 const* o = m_expressionClasses.knownConstant(offsetToStart); u256 const* l = m_expressionClasses.knownConstant(length); if (l && *l == 0) @@ -462,6 +509,7 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) for (Id arg: boost::adaptors::reverse(arguments)) generateClassElement(arg); + SourceLocation const& location = expr.item->getLocation(); // The arguments are somewhere on the stack now, so it remains to move them at the correct place. // This is quite difficult as sometimes, the values also have to removed in this process // (if canBeRemoved() returns true) and the two arguments can be equal. For now, this is @@ -469,42 +517,42 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) if (arguments.size() == 1) { if (canBeRemoved(arguments[0], _c)) - appendOrRemoveSwap(classElementPosition(arguments[0])); + appendOrRemoveSwap(classElementPosition(arguments[0]), location); else - appendDup(classElementPosition(arguments[0])); + appendDup(classElementPosition(arguments[0]), location); } else if (arguments.size() == 2) { if (canBeRemoved(arguments[1], _c)) { - appendOrRemoveSwap(classElementPosition(arguments[1])); + appendOrRemoveSwap(classElementPosition(arguments[1]), location); if (arguments[0] == arguments[1]) - appendDup(m_stackHeight); + appendDup(m_stackHeight, location); else if (canBeRemoved(arguments[0], _c)) { - appendOrRemoveSwap(m_stackHeight - 1); - appendOrRemoveSwap(classElementPosition(arguments[0])); + appendOrRemoveSwap(m_stackHeight - 1, location); + appendOrRemoveSwap(classElementPosition(arguments[0]), location); } else - appendDup(classElementPosition(arguments[0])); + appendDup(classElementPosition(arguments[0]), location); } else { if (arguments[0] == arguments[1]) { - appendDup(classElementPosition(arguments[0])); - appendDup(m_stackHeight); + appendDup(classElementPosition(arguments[0]), location); + appendDup(m_stackHeight, location); } else if (canBeRemoved(arguments[0], _c)) { - appendOrRemoveSwap(classElementPosition(arguments[0])); - appendDup(classElementPosition(arguments[1])); - appendOrRemoveSwap(m_stackHeight - 1); + appendOrRemoveSwap(classElementPosition(arguments[0]), location); + appendDup(classElementPosition(arguments[1]), location); + appendOrRemoveSwap(m_stackHeight - 1, location); } else { - appendDup(classElementPosition(arguments[1])); - appendDup(classElementPosition(arguments[0])); + appendDup(classElementPosition(arguments[1]), location); + appendDup(classElementPosition(arguments[0]), location); } } } @@ -521,7 +569,7 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) !m_generatedItems.empty() && m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) // this will not append a swap but remove the one that is already there - appendOrRemoveSwap(m_stackHeight - 1); + appendOrRemoveSwap(m_stackHeight - 1, location); for (auto arg: arguments) if (canBeRemoved(arg, _c)) m_classPositions[arg] = c_invalidPosition; @@ -582,17 +630,17 @@ bool CSECodeGenerator::removeStackTopIfPossible() return true; } -void CSECodeGenerator::appendDup(int _fromPosition) +void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _location) { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); int instructionNum = 1 + m_stackHeight - _fromPosition; assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(dupInstruction(instructionNum))); + appendItem(AssemblyItem(dupInstruction(instructionNum), _location)); m_stack[m_stackHeight] = m_stack[_fromPosition]; } -void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition) +void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location) { assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); if (_fromPosition == m_stackHeight) @@ -600,7 +648,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition) int instructionNum = m_stackHeight - _fromPosition; assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); - appendItem(AssemblyItem(swapInstruction(instructionNum))); + appendItem(AssemblyItem(swapInstruction(instructionNum), _location)); // The value of a class can be present in multiple locations on the stack. We only update the // "canonical" one that is tracked by m_classPositions if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight) diff --git a/libevmcore/CommonSubexpressionEliminator.h b/libevmcore/CommonSubexpressionEliminator.h index 660e9dacc..6001f1780 100644 --- a/libevmcore/CommonSubexpressionEliminator.h +++ b/libevmcore/CommonSubexpressionEliminator.h @@ -99,26 +99,26 @@ private: /// Assigns a new equivalence class to the next sequence number of the given stack element. void setStackElement(int _stackHeight, Id _class); /// Swaps the given stack elements in their next sequence number. - void swapStackElements(int _stackHeightA, int _stackHeightB); + void swapStackElements(int _stackHeightA, int _stackHeightB, SourceLocation const& _location); /// Retrieves the current equivalence class fo the given stack element (or generates a new /// one if it does not exist yet). - Id stackElement(int _stackHeight); + Id stackElement(int _stackHeight, SourceLocation const& _location); /// @returns the equivalence class id of the special initial stack element at the given height /// (must not be positive). - Id initialStackElement(int _stackHeight); + Id initialStackElement(int _stackHeight, SourceLocation const& _location); /// Increments the sequence number, deletes all storage information that might be overwritten /// and stores the new value at the given slot. - void storeInStorage(Id _slot, Id _value); + void storeInStorage(Id _slot, Id _value, SourceLocation const& _location); /// Retrieves the current value at the given slot in storage or creates a new special sload class. - Id loadFromStorage(Id _slot); + Id loadFromStorage(Id _slot, SourceLocation const& _location); /// Increments the sequence number, deletes all memory information that might be overwritten /// and stores the new value at the given slot. - void storeInMemory(Id _slot, Id _value); + void storeInMemory(Id _slot, Id _value, SourceLocation const& _location); /// Retrieves the current value at the given slot in memory or creates a new special mload class. - Id loadFromMemory(Id _slot); + Id loadFromMemory(Id _slot, SourceLocation const& _location); /// Finds or creates a new expression that applies the sha3 hash function to the contents in memory. - Id applySha3(Id _start, Id _length); + Id applySha3(Id _start, Id _length, SourceLocation const& _location); /// Current stack height, can be negative. int m_stackHeight = 0; @@ -188,10 +188,10 @@ private: bool removeStackTopIfPossible(); /// Appends a dup instruction to m_generatedItems to retrieve the element at the given stack position. - void appendDup(int _fromPosition); + void appendDup(int _fromPosition, SourceLocation const& _location); /// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position. /// @note this might also remove the last item if it exactly the same swap instruction. - void appendOrRemoveSwap(int _fromPosition); + void appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location); /// Appends the given assembly item. void appendItem(AssemblyItem const& _item); diff --git a/libevmcore/ExpressionClasses.cpp b/libevmcore/ExpressionClasses.cpp index 81beaac7e..7c5d9ad72 100644 --- a/libevmcore/ExpressionClasses.cpp +++ b/libevmcore/ExpressionClasses.cpp @@ -64,10 +64,7 @@ ExpressionClasses::Id ExpressionClasses::find( return it->id; if (_copyItem) - { - m_spareAssemblyItem.push_back(make_shared(_item)); - exp.item = m_spareAssemblyItem.back().get(); - } + exp.item = storeItem(_item); ExpressionClasses::Id id = tryToSimplify(exp); if (id < m_representatives.size()) @@ -115,6 +112,12 @@ u256 const* ExpressionClasses::knownConstant(Id _c) return &constant.d(); } +AssemblyItem const* ExpressionClasses::storeItem(AssemblyItem const& _item) +{ + m_spareAssemblyItems.push_back(make_shared(_item)); + return m_spareAssemblyItems.back().get(); +} + string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const { Expression const& expr = representative(_id); @@ -292,7 +295,7 @@ ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr, //cout << "with rule " << rule.first.toString() << endl; //ExpressionTemplate t(rule.second()); //cout << "to " << rule.second().toString() << endl; - return rebuildExpression(ExpressionTemplate(rule.second())); + return rebuildExpression(ExpressionTemplate(rule.second(), _expr.item->getLocation())); } } @@ -350,6 +353,11 @@ bool Pattern::matches(Expression const& _expr, ExpressionClasses const& _classes return true; } +AssemblyItem Pattern::toAssemblyItem(SourceLocation const& _location) const +{ + return AssemblyItem(m_type, m_data, _location); +} + string Pattern::toString() const { stringstream s; @@ -399,7 +407,7 @@ Pattern::Expression const& Pattern::matchGroupValue() const } -ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern) +ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location) { if (_pattern.matchGroup()) { @@ -409,10 +417,10 @@ ExpressionTemplate::ExpressionTemplate(Pattern const& _pattern) else { hasId = false; - item = _pattern.toAssemblyItem(); + item = _pattern.toAssemblyItem(_location); } for (auto const& arg: _pattern.arguments()) - arguments.push_back(ExpressionTemplate(arg)); + arguments.push_back(ExpressionTemplate(arg, _location)); } string ExpressionTemplate::toString() const diff --git a/libevmcore/ExpressionClasses.h b/libevmcore/ExpressionClasses.h index dba7384ec..d5bf8e547 100644 --- a/libevmcore/ExpressionClasses.h +++ b/libevmcore/ExpressionClasses.h @@ -88,6 +88,10 @@ public: /// and a nullptr otherwise. u256 const* knownConstant(Id _c); + /// Stores a copy of the given AssemblyItem and returns a pointer to the copy that is valid for + /// the lifetime of the ExpressionClasses object. + AssemblyItem const* storeItem(AssemblyItem const& _item); + std::string fullDAGToString(Id _id) const; private: @@ -105,7 +109,7 @@ private: std::vector m_representatives; /// All expression ever encountered. std::set m_expressions; - std::vector> m_spareAssemblyItem; + std::vector> m_spareAssemblyItems; }; /** @@ -134,7 +138,7 @@ public: unsigned matchGroup() const { return m_matchGroup; } bool matches(Expression const& _expr, ExpressionClasses const& _classes) const; - AssemblyItem toAssemblyItem() const { return AssemblyItem(m_type, m_data); } + AssemblyItem toAssemblyItem(SourceLocation const& _location) const; std::vector arguments() const { return m_arguments; } /// @returns the id of the matched expression if this pattern is part of a match group. @@ -163,7 +167,7 @@ struct ExpressionTemplate { using Expression = ExpressionClasses::Expression; using Id = ExpressionClasses::Id; - explicit ExpressionTemplate(Pattern const& _pattern); + explicit ExpressionTemplate(Pattern const& _pattern, SourceLocation const& _location); std::string toString() const; bool hasId = false; /// Id of the matched expression, if available. diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index af9b51467..ceb9c68d9 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -84,9 +85,20 @@ public: AssemblyItems getCSE(AssemblyItems const& _input) { + // add dummy locations to each item so that we can check that they are not deleted + AssemblyItems input = _input; + for (AssemblyItem& item: input) + item.setLocation(SourceLocation(1, 3, make_shared(""))); + eth::CommonSubexpressionEliminator cse; - BOOST_REQUIRE(cse.feedItems(_input.begin(), _input.end()) == _input.end()); - return cse.getOptimizedItems(); + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end()); + AssemblyItems output = cse.getOptimizedItems(); + + for (AssemblyItem const& item: output) + { + BOOST_CHECK(item == Instruction::POP || !item.getLocation().isEmpty()); + } + return output; } void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation)