From 1492fe2a88a67c12a544ef48857e94c2f10e1892 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2015 18:31:21 +0200 Subject: [PATCH] Store alternative stack locations during code generation. --- libevmasm/CommonSubexpressionEliminator.cpp | 80 +++++++++++---------- libevmasm/CommonSubexpressionEliminator.h | 8 +-- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 5beb7966f..e369c9dbc 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -121,10 +121,7 @@ AssemblyItems CSECodeGenerator::generateCode( m_stack = _initialStack; m_targetStack = _targetStackContents; for (auto const& item: m_stack) - if (!m_classPositions.count(item.second)) - m_classPositions[item.second] = item.first; - - // @todo: provide information about the positions of copies of class elements + m_classPositions[item.second].insert(item.first); // generate the dependency graph starting from final storage and memory writes and target stack contents for (auto const& p: m_storeOperations) @@ -152,11 +149,12 @@ AssemblyItems CSECodeGenerator::generateCode( { if (m_stack.count(targetItem.first) && m_stack.at(targetItem.first) == targetItem.second) continue; // already there - int position = generateClassElement(targetItem.second); - assertThrow(position != c_invalidPosition, OptimizerException, ""); - if (position == targetItem.first) + generateClassElement(targetItem.second); + assertThrow(!m_classPositions[targetItem.second].empty(), OptimizerException, ""); + if (m_classPositions[targetItem.second].count(targetItem.first)) continue; SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation(); + int position = classElementPosition(targetItem.second); if (position < targetItem.first) // it is already at its target, we need another copy appendDup(position, location); @@ -266,19 +264,23 @@ void CSECodeGenerator::addDependencies(Id _c) } } -int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) +void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) { + for (auto it: m_classPositions) + for (auto p: it.second) + if (p > m_stackHeight) + assertThrow(false, OptimizerException, ""); // do some cleanup removeStackTopIfPossible(); if (m_classPositions.count(_c)) { assertThrow( - m_classPositions[_c] != c_invalidPosition, + !m_classPositions[_c].empty(), OptimizerException, "Element already removed but still needed." ); - return m_classPositions[_c]; + return; } ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c); assertThrow( @@ -351,16 +353,16 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) // this will not append a swap but remove the one that is already there appendOrRemoveSwap(m_stackHeight - 1, location); - for (auto arg: arguments) - if (m_classPositions[arg] != c_invalidPosition && canBeRemoved(arg, _c)) - m_classPositions[arg] = c_invalidPosition; for (size_t i = 0; i < arguments.size(); ++i) + { + m_classPositions[m_stack[m_stackHeight - i]].erase(m_stackHeight - i); m_stack.erase(m_stackHeight - i); + } appendItem(*expr.item); if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1) { m_stack[m_stackHeight] = _c; - return m_classPositions[_c] = m_stackHeight; + m_classPositions[_c].insert(m_stackHeight); } else { @@ -369,18 +371,18 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced) OptimizerException, "Invalid number of return values." ); - return m_classPositions[_c] = c_invalidPosition; + m_classPositions[_c]; // ensure it is created to mark the expression as generated } } int CSECodeGenerator::classElementPosition(Id _id) const { assertThrow( - m_classPositions.count(_id) && m_classPositions.at(_id) != c_invalidPosition, + m_classPositions.count(_id) && !m_classPositions.at(_id).empty(), OptimizerException, "Element requested but is not present." ); - return m_classPositions.at(_id); + return *max_element(m_classPositions.at(_id).begin(), m_classPositions.at(_id).end()); } bool CSECodeGenerator::canBeRemoved(Id _element, Id _result, int _fromPosition) @@ -389,20 +391,19 @@ bool CSECodeGenerator::canBeRemoved(Id _element, Id _result, int _fromPosition) if (_fromPosition == c_invalidPosition) _fromPosition = classElementPosition(_element); - bool isCopy = _fromPosition != classElementPosition(_element); + 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 isCopy && (!m_targetStack.count(_fromPosition) || m_targetStack[_fromPosition] != _element); - else if (isCopy) - // It is only a copy, can be removed. - return true; - - // Can be removed unless it is needed by a class that has not been computed yet. - // Note that m_classPositions also includes classes that were deleted in the meantime. - auto range = m_neededBy.equal_range(_element); - for (auto it = range.first; it != range.second; ++it) - if (it->second != _result && !m_classPositions.count(it->second)) - return false; + return haveCopy && (!m_targetStack.count(_fromPosition) || m_targetStack[_fromPosition] != _element); + else if (!haveCopy) + { + // Can be removed unless it is needed by a class that has not been computed yet. + // Note that m_classPositions also includes classes that were deleted in the meantime. + auto range = m_neededBy.equal_range(_element); + for (auto it = range.first; it != range.second; ++it) + if (it->second != _result && !m_classPositions.count(it->second)) + return false; + } return true; } @@ -414,9 +415,9 @@ bool CSECodeGenerator::removeStackTopIfPossible() Id top = m_stack[m_stackHeight]; if (!canBeRemoved(top, Id(-1), m_stackHeight)) return false; - m_generatedItems.push_back(AssemblyItem(Instruction::POP)); + m_classPositions[m_stack[m_stackHeight]].erase(m_stackHeight); m_stack.erase(m_stackHeight); - m_stackHeight--; + appendItem(AssemblyItem(Instruction::POP)); return true; } @@ -428,6 +429,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); appendItem(AssemblyItem(dupInstruction(instructionNum), _location)); m_stack[m_stackHeight] = m_stack[_fromPosition]; + m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight); } void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location) @@ -439,13 +441,15 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); 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) - m_classPositions[m_stack[m_stackHeight]] = _fromPosition; - if (m_classPositions[m_stack[_fromPosition]] == _fromPosition) - m_classPositions[m_stack[_fromPosition]] = m_stackHeight; - swap(m_stack[m_stackHeight], m_stack[_fromPosition]); + + if (m_stack[m_stackHeight] != m_stack[_fromPosition]) + { + m_classPositions[m_stack[m_stackHeight]].erase(m_stackHeight); + m_classPositions[m_stack[m_stackHeight]].insert(_fromPosition); + m_classPositions[m_stack[_fromPosition]].erase(_fromPosition); + m_classPositions[m_stack[_fromPosition]].insert(m_stackHeight); + swap(m_stack[m_stackHeight], m_stack[_fromPosition]); + } if (m_generatedItems.size() >= 2 && SemanticInformation::isSwapInstruction(m_generatedItems.back()) && *(m_generatedItems.end() - 2) == m_generatedItems.back()) diff --git a/libevmasm/CommonSubexpressionEliminator.h b/libevmasm/CommonSubexpressionEliminator.h index 2a9a31255..a35e31d90 100644 --- a/libevmasm/CommonSubexpressionEliminator.h +++ b/libevmasm/CommonSubexpressionEliminator.h @@ -119,10 +119,8 @@ private: void addDependencies(Id _c); /// Produce code that generates the given element if it is not yet present. - /// @returns the stack position of the element or c_invalidPosition if it does not actually - /// generate a value on the stack. /// @param _allowSequenced indicates that sequence-constrained operations are allowed - int generateClassElement(Id _c, bool _allowSequenced = false); + void generateClassElement(Id _c, bool _allowSequenced = false); /// @returns the position of the representative of the given id on the stack. /// @note throws an exception if it is not on the stack. int classElementPosition(Id _id) const; @@ -151,8 +149,8 @@ private: std::multimap m_neededBy; /// Current content of the stack. std::map m_stack; - /// Current positions of equivalence classes, equal to c_invalidPosition if already deleted. - std::map m_classPositions; + /// Current positions of equivalence classes, equal to the empty set if already deleted. + std::map> m_classPositions; /// The actual eqivalence class items and how to compute them. ExpressionClasses& m_expressionClasses;