Browse Source

Code generation part 1.

cl-refactor
chriseth 10 years ago
parent
commit
6f54f1046a
  1. 167
      libevmcore/CommonSubexpressionEliminator.cpp
  2. 39
      libevmcore/CommonSubexpressionEliminator.h

167
libevmcore/CommonSubexpressionEliminator.cpp

@ -22,6 +22,7 @@
*/
#include <functional>
#include <boost/range/adaptor/reversed.hpp>
#include <libevmcore/CommonSubexpressionEliminator.h>
#include <libevmcore/Assembly.h>
@ -56,16 +57,19 @@ vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
streamEquivalenceClass(cout, eqClass);
cout << "----------------------------" << endl;
map<int, EquivalenceClassId> currentStackContents;
map<int, EquivalenceClassId> targetStackContents;
int minStackHeight = m_stackHeight;
if (m_stackElements.size() > 0)
minStackHeight = min(minStackHeight, m_stackElements.begin()->first.first);
for (int stackHeight = minStackHeight; stackHeight <= m_stackHeight; ++stackHeight)
{
if (stackHeight <= 0)
currentStackContents[stackHeight] = getClass(AssemblyItem(dupInstruction(1 - stackHeight)));
targetStackContents[stackHeight] = getStackElement(stackHeight);
}
CSECodeGenerator generator;
return generator.generateCode(m_stackHeight, targetStackContents, m_equivalenceClasses);
return CSECodeGenerator().generateCode(currentStackContents, targetStackContents, m_equivalenceClasses);
}
bool CommonSubexpressionEliminator::breaksBasicBlock(AssemblyItem const& _item)
@ -234,13 +238,160 @@ unsigned CommonSubexpressionEliminator::getNextStackElementSequence(int _stackHe
return 0;
}
AssemblyItems CSECodeGenerator::generateCode(
int _targetStackHeight,
map<int, EquivalenceClassId> const& _currentStack,
map<int, EquivalenceClassId> const& _targetStackContents,
vector<pair<const AssemblyItem*, EquivalenceClassIds>> const& _equivalenceClasses)
vector<pair<AssemblyItem const*, EquivalenceClassIds>> const& _equivalenceClasses
)
{
m_generatedItems.clear();
m_classRequestCount.clear();
// reset
*this = move(CSECodeGenerator());
m_stack = _currentStack;
m_equivalenceClasses = _equivalenceClasses;
for (auto const& item: m_stack)
m_classPositions[item.second] = item.first;
// generate the dependency graph
for (auto const& stackContent: _targetStackContents)
{
m_finalClasses.insert(stackContent.second);
addDependencies(stackContent.second);
}
for (auto const& cid: m_finalClasses)
generateClassElement(cid);
// @TODO shuffle and copy the elements
cout << "--------------- generated code: ---------------" << endl;
for (auto const& it: m_generatedItems)
cout << it << endl;
cout << "-----------------------------" << endl;
return m_generatedItems;
}
void CSECodeGenerator::addDependencies(EquivalenceClassId _c)
{
if (m_neededBy.count(_c))
return;
for (EquivalenceClassId argument: m_equivalenceClasses[_c].second)
{
addDependencies(argument);
m_neededBy.insert(make_pair(argument, _c));
}
}
int CSECodeGenerator::generateClassElement(EquivalenceClassId _c)
{
if (m_classPositions.count(_c))
return m_classPositions[_c];
assertThrow(
m_classPositions[_c] != c_invalidPosition,
OptimizerException,
"Element already removed but still needed."
);
EquivalenceClassIds const& arguments = m_equivalenceClasses[_c].second;
for (EquivalenceClassId arg: boost::adaptors::reverse(arguments))
generateClassElement(arg);
if (arguments.size() == 1)
{
if (canBeRemoved(arguments[0], _c))
appendSwap(generateClassElement(arguments[0]));
else
appendDup(generateClassElement(arguments[0]));
}
else if (arguments.size() == 2)
{
if (canBeRemoved(arguments[1], _c))
{
appendSwap(generateClassElement(arguments[1]));
if (arguments[0] == arguments[1])
appendDup(m_stackHeight);
else if (canBeRemoved(arguments[0], _c))
{
appendSwap(m_stackHeight - 1);
appendSwap(generateClassElement(arguments[1]));
}
else
appendDup(generateClassElement(arguments[1]));
}
else
{
if (arguments[0] == arguments[1])
{
appendDup(generateClassElement(arguments[0]));
appendDup(m_stackHeight);
}
else if (canBeRemoved(arguments[0], _c))
{
appendSwap(generateClassElement(arguments[0]));
appendDup(generateClassElement(arguments[1]));
appendSwap(m_stackHeight - 1);
}
else
{
appendDup(generateClassElement(arguments[1]));
appendDup(generateClassElement(arguments[0]));
}
}
}
else
assertThrow(
arguments.size() <= 2,
OptimizerException,
"Opcodes with more than two arguments not implemented yet."
);
for (auto arg: arguments)
if (canBeRemoved(arg, _c))
m_classPositions[arguments[1]] = c_invalidPosition;
appendItem(*m_equivalenceClasses[_c].first);
m_stack[m_stackHeight] = _c;
return m_classPositions[_c] = m_stackHeight;
}
bool CSECodeGenerator::canBeRemoved(EquivalenceClassId _element, EquivalenceClassId _result)
{
// Returns false if _element is finally needed or is needed by a class that has not been
// computed yet. Note that m_classPositions also includes classes that were deleted in the meantime.
if (m_finalClasses.count(_element))
return false;
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;
}
void CSECodeGenerator::appendDup(int _fromPosition)
{
m_generatedItems.push_back(AssemblyItem(swapInstruction(1 + m_stackHeight - _fromPosition)));
int nr = 1 + m_stackHeight - _fromPosition;
assertThrow(1 <= nr && nr <= 16, OptimizerException, "Stack too deep.");
m_generatedItems.push_back(AssemblyItem(dupInstruction(nr)));
m_stackHeight++;
m_stack[m_stackHeight] = m_stack[_fromPosition];
}
void CSECodeGenerator::appendSwap(int _fromPosition)
{
if (_fromPosition == m_stackHeight)
return;
int nr = m_stackHeight - _fromPosition;
assertThrow(1 <= nr && nr <= 16, OptimizerException, "Stack too deep.");
m_generatedItems.push_back(AssemblyItem(swapInstruction(nr)));
// only update if they are the "canonical" positions
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]);
}
void CSECodeGenerator::appendItem(AssemblyItem const& _item)
{
m_generatedItems.push_back(_item);
m_stackHeight += _item.deposit();
}

39
libevmcore/CommonSubexpressionEliminator.h

@ -26,6 +26,7 @@
#include <vector>
#include <map>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Exceptions.h>
namespace dev
{
@ -98,19 +99,49 @@ class CSECodeGenerator
{
public:
/// @returns the assembly items generated from the given requirements
/// @param _targetStackHeight target stack height starting from an assumed initial stack height of zero
/// @param _currentStack current contents of the stack (up to stack height of zero)
/// @param _targetStackContents final contents of the stack, by stack height relative to initial
/// @param _equivalenceClasses equivalence classes as expressions of how to compute them
AssemblyItems generateCode(
int _targetStackHeight,
std::map<int, EquivalenceClassId> const& _currentStack,
std::map<int, EquivalenceClassId> const& _targetStackContents,
std::vector<std::pair<AssemblyItem const*, EquivalenceClassIds>> const& _equivalenceClasses
);
private:
/// Recursively discovers all dependencies to @a m_requests.
void addDependencies(EquivalenceClassId _c);
/// Produce code that generates the given element if it is not yet present.
/// @returns the stack position of the element.
int generateClassElement(EquivalenceClassId _c);
/// @returns true if @a _element can be removed while computing @a _result.
bool canBeRemoved(EquivalenceClassId _element, EquivalenceClassId _result);
/// Appends a dup instruction to m_generatedItems to retrieve the element at the given stack position.
void appendDup(int _fromPosition);
/// Appends a swap instruction to m_generatedItems to retrieve the element at the given stack position.
void appendSwap(int _fromPosition);
/// Appends the given assembly item.
void appendItem(AssemblyItem const& _item);
static const int c_invalidPosition = std::numeric_limits<int>::min();
AssemblyItems m_generatedItems;
/// Number of requests for an equivalence class, used as a reference counter.
std::map<EquivalenceClassId, unsigned> m_classRequestCount;
/// Current height of the stack relative to the start.
int m_stackHeight = 0;
/// If (b, a) is in m_requests then b is needed to compute a.
std::multimap<EquivalenceClassId, EquivalenceClassId> m_neededBy;
/// Current content of the stack.
std::map<int, EquivalenceClassId> m_stack;
/// Current positions of equivalence classes, equal to c_invalidPosition if already deleted.
std::map<EquivalenceClassId, int> m_classPositions;
/// The actual eqivalence class items and how to compute them.
std::vector<std::pair<AssemblyItem const*, EquivalenceClassIds>> m_equivalenceClasses;
/// The set of equivalence classes that should be present on the stack at the end.
std::set<EquivalenceClassId> m_finalClasses;
};
template <class _AssemblyItemIterator>

Loading…
Cancel
Save