mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Store alternative stack locations during code generation.
This commit is contained in:
parent
9d3f0de31b
commit
2fbcb5b9c8
@ -121,10 +121,7 @@ AssemblyItems CSECodeGenerator::generateCode(
|
|||||||
m_stack = _initialStack;
|
m_stack = _initialStack;
|
||||||
m_targetStack = _targetStackContents;
|
m_targetStack = _targetStackContents;
|
||||||
for (auto const& item: m_stack)
|
for (auto const& item: m_stack)
|
||||||
if (!m_classPositions.count(item.second))
|
m_classPositions[item.second].insert(item.first);
|
||||||
m_classPositions[item.second] = item.first;
|
|
||||||
|
|
||||||
// @todo: provide information about the positions of copies of class elements
|
|
||||||
|
|
||||||
// generate the dependency graph starting from final storage and memory writes and target stack contents
|
// generate the dependency graph starting from final storage and memory writes and target stack contents
|
||||||
for (auto const& p: m_storeOperations)
|
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)
|
if (m_stack.count(targetItem.first) && m_stack.at(targetItem.first) == targetItem.second)
|
||||||
continue; // already there
|
continue; // already there
|
||||||
int position = generateClassElement(targetItem.second);
|
generateClassElement(targetItem.second);
|
||||||
assertThrow(position != c_invalidPosition, OptimizerException, "");
|
assertThrow(!m_classPositions[targetItem.second].empty(), OptimizerException, "");
|
||||||
if (position == targetItem.first)
|
if (m_classPositions[targetItem.second].count(targetItem.first))
|
||||||
continue;
|
continue;
|
||||||
SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation();
|
SourceLocation const& location = m_expressionClasses.representative(targetItem.second).item->getLocation();
|
||||||
|
int position = classElementPosition(targetItem.second);
|
||||||
if (position < targetItem.first)
|
if (position < targetItem.first)
|
||||||
// it is already at its target, we need another copy
|
// it is already at its target, we need another copy
|
||||||
appendDup(position, location);
|
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
|
// do some cleanup
|
||||||
removeStackTopIfPossible();
|
removeStackTopIfPossible();
|
||||||
|
|
||||||
if (m_classPositions.count(_c))
|
if (m_classPositions.count(_c))
|
||||||
{
|
{
|
||||||
assertThrow(
|
assertThrow(
|
||||||
m_classPositions[_c] != c_invalidPosition,
|
!m_classPositions[_c].empty(),
|
||||||
OptimizerException,
|
OptimizerException,
|
||||||
"Element already removed but still needed."
|
"Element already removed but still needed."
|
||||||
);
|
);
|
||||||
return m_classPositions[_c];
|
return;
|
||||||
}
|
}
|
||||||
ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c);
|
ExpressionClasses::Expression const& expr = m_expressionClasses.representative(_c);
|
||||||
assertThrow(
|
assertThrow(
|
||||||
@ -351,16 +353,16 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
|||||||
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
|
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
|
||||||
// this will not append a swap but remove the one that is already there
|
// this will not append a swap but remove the one that is already there
|
||||||
appendOrRemoveSwap(m_stackHeight - 1, location);
|
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)
|
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);
|
m_stack.erase(m_stackHeight - i);
|
||||||
|
}
|
||||||
appendItem(*expr.item);
|
appendItem(*expr.item);
|
||||||
if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1)
|
if (expr.item->type() != Operation || instructionInfo(expr.item->instruction()).ret == 1)
|
||||||
{
|
{
|
||||||
m_stack[m_stackHeight] = _c;
|
m_stack[m_stackHeight] = _c;
|
||||||
return m_classPositions[_c] = m_stackHeight;
|
m_classPositions[_c].insert(m_stackHeight);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -369,18 +371,18 @@ int CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
|
|||||||
OptimizerException,
|
OptimizerException,
|
||||||
"Invalid number of return values."
|
"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
|
int CSECodeGenerator::classElementPosition(Id _id) const
|
||||||
{
|
{
|
||||||
assertThrow(
|
assertThrow(
|
||||||
m_classPositions.count(_id) && m_classPositions.at(_id) != c_invalidPosition,
|
m_classPositions.count(_id) && !m_classPositions.at(_id).empty(),
|
||||||
OptimizerException,
|
OptimizerException,
|
||||||
"Element requested but is not present."
|
"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)
|
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)
|
if (_fromPosition == c_invalidPosition)
|
||||||
_fromPosition = classElementPosition(_element);
|
_fromPosition = classElementPosition(_element);
|
||||||
|
|
||||||
bool isCopy = _fromPosition != classElementPosition(_element);
|
bool haveCopy = m_classPositions.at(_element).size() > 1;
|
||||||
if (m_finalClasses.count(_element))
|
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.
|
// 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);
|
return haveCopy && (!m_targetStack.count(_fromPosition) || m_targetStack[_fromPosition] != _element);
|
||||||
else if (isCopy)
|
else if (!haveCopy)
|
||||||
// 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.
|
// 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.
|
// Note that m_classPositions also includes classes that were deleted in the meantime.
|
||||||
auto range = m_neededBy.equal_range(_element);
|
auto range = m_neededBy.equal_range(_element);
|
||||||
for (auto it = range.first; it != range.second; ++it)
|
for (auto it = range.first; it != range.second; ++it)
|
||||||
if (it->second != _result && !m_classPositions.count(it->second))
|
if (it->second != _result && !m_classPositions.count(it->second))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,9 +415,9 @@ bool CSECodeGenerator::removeStackTopIfPossible()
|
|||||||
Id top = m_stack[m_stackHeight];
|
Id top = m_stack[m_stackHeight];
|
||||||
if (!canBeRemoved(top, Id(-1), m_stackHeight))
|
if (!canBeRemoved(top, Id(-1), m_stackHeight))
|
||||||
return false;
|
return false;
|
||||||
m_generatedItems.push_back(AssemblyItem(Instruction::POP));
|
m_classPositions[m_stack[m_stackHeight]].erase(m_stackHeight);
|
||||||
m_stack.erase(m_stackHeight);
|
m_stack.erase(m_stackHeight);
|
||||||
m_stackHeight--;
|
appendItem(AssemblyItem(Instruction::POP));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,6 +429,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat
|
|||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(dupInstruction(instructionNum), _location));
|
appendItem(AssemblyItem(dupInstruction(instructionNum), _location));
|
||||||
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
m_stack[m_stackHeight] = m_stack[_fromPosition];
|
||||||
|
m_classPositions[m_stack[m_stackHeight]].insert(m_stackHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation const& _location)
|
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(instructionNum <= 16, StackTooDeepException, "Stack too deep.");
|
||||||
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
|
||||||
appendItem(AssemblyItem(swapInstruction(instructionNum), _location));
|
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_stack[m_stackHeight] != m_stack[_fromPosition])
|
||||||
if (m_classPositions[m_stack[m_stackHeight]] == m_stackHeight)
|
{
|
||||||
m_classPositions[m_stack[m_stackHeight]] = _fromPosition;
|
m_classPositions[m_stack[m_stackHeight]].erase(m_stackHeight);
|
||||||
if (m_classPositions[m_stack[_fromPosition]] == _fromPosition)
|
m_classPositions[m_stack[m_stackHeight]].insert(_fromPosition);
|
||||||
m_classPositions[m_stack[_fromPosition]] = m_stackHeight;
|
m_classPositions[m_stack[_fromPosition]].erase(_fromPosition);
|
||||||
|
m_classPositions[m_stack[_fromPosition]].insert(m_stackHeight);
|
||||||
swap(m_stack[m_stackHeight], m_stack[_fromPosition]);
|
swap(m_stack[m_stackHeight], m_stack[_fromPosition]);
|
||||||
|
}
|
||||||
if (m_generatedItems.size() >= 2 &&
|
if (m_generatedItems.size() >= 2 &&
|
||||||
SemanticInformation::isSwapInstruction(m_generatedItems.back()) &&
|
SemanticInformation::isSwapInstruction(m_generatedItems.back()) &&
|
||||||
*(m_generatedItems.end() - 2) == m_generatedItems.back())
|
*(m_generatedItems.end() - 2) == m_generatedItems.back())
|
||||||
|
@ -119,10 +119,8 @@ private:
|
|||||||
void addDependencies(Id _c);
|
void addDependencies(Id _c);
|
||||||
|
|
||||||
/// Produce code that generates the given element if it is not yet present.
|
/// 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
|
/// @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.
|
/// @returns the position of the representative of the given id on the stack.
|
||||||
/// @note throws an exception if it is not on the stack.
|
/// @note throws an exception if it is not on the stack.
|
||||||
int classElementPosition(Id _id) const;
|
int classElementPosition(Id _id) const;
|
||||||
@ -151,8 +149,8 @@ private:
|
|||||||
std::multimap<Id, Id> m_neededBy;
|
std::multimap<Id, Id> m_neededBy;
|
||||||
/// Current content of the stack.
|
/// Current content of the stack.
|
||||||
std::map<int, Id> m_stack;
|
std::map<int, Id> m_stack;
|
||||||
/// Current positions of equivalence classes, equal to c_invalidPosition if already deleted.
|
/// Current positions of equivalence classes, equal to the empty set if already deleted.
|
||||||
std::map<Id, int> m_classPositions;
|
std::map<Id, std::set<int>> m_classPositions;
|
||||||
|
|
||||||
/// The actual eqivalence class items and how to compute them.
|
/// The actual eqivalence class items and how to compute them.
|
||||||
ExpressionClasses& m_expressionClasses;
|
ExpressionClasses& m_expressionClasses;
|
||||||
|
Loading…
Reference in New Issue
Block a user