Browse Source

Refactoring: Extract equivalence class container.

cl-refactor
chriseth 10 years ago
parent
commit
ea6d5c2c98
  1. 154
      libevmcore/CommonSubexpressionEliminator.cpp
  2. 52
      libevmcore/CommonSubexpressionEliminator.h
  3. 110
      libevmcore/ExpressionClasses.cpp
  4. 70
      libevmcore/ExpressionClasses.h

154
libevmcore/CommonSubexpressionEliminator.cpp

@ -32,17 +32,17 @@ using namespace dev::eth;
vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
{
map<int, EquivalenceClassId> initialStackContents;
map<int, EquivalenceClassId> targetStackContents;
map<int, ExpressionClasses::Id> initialStackContents;
map<int, ExpressionClasses::Id> targetStackContents;
int minHeight = m_stackHeight + 1;
if (!m_stackElements.empty())
minHeight = min(minHeight, m_stackElements.begin()->first.first);
for (int height = minHeight; height <= max(0, m_stackHeight); ++height)
{
// make sure it is created
EquivalenceClassId c = getStackElement(height);
ExpressionClasses::Id c = getStackElement(height);
if (height <= 0)
initialStackContents[height] = getClass(AssemblyItem(dupInstruction(1 - height)));
initialStackContents[height] = m_expressionClasses.find(AssemblyItem(dupInstruction(1 - height)));
if (height <= m_stackHeight)
targetStackContents[height] = c;
}
@ -50,21 +50,21 @@ vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
// Debug info:
//stream(cout, currentStackContents, targetStackContents);
return CSECodeGenerator().generateCode(initialStackContents, targetStackContents, m_equivalenceClasses);
return CSECodeGenerator(m_expressionClasses).generateCode(initialStackContents, targetStackContents);
}
ostream& CommonSubexpressionEliminator::stream(
ostream& _out,
map<int, EquivalenceClassId> _currentStack,
map<int, EquivalenceClassId> _targetStack
map<int, ExpressionClasses::Id> _currentStack,
map<int, ExpressionClasses::Id> _targetStack
) const
{
auto streamEquivalenceClass = [this](ostream& _out, EquivalenceClassId _id)
auto streamExpressionClass = [this](ostream& _out, ExpressionClasses::Id _id)
{
auto const& eqClass = m_equivalenceClasses.at(_id);
_out << " " << _id << ": " << *eqClass.first;
auto const& expr = m_expressionClasses.representative(_id);
_out << " " << _id << ": " << *expr.item;
_out << "(";
for (EquivalenceClassId arg: eqClass.second)
for (ExpressionClasses::Id arg: expr.arguments)
_out << dec << arg << ",";
_out << ")" << endl;
};
@ -75,23 +75,23 @@ ostream& CommonSubexpressionEliminator::stream(
for (auto const& it: m_stackElements)
{
_out << " " << dec << it.first.first << "(" << it.first.second << ") = ";
streamEquivalenceClass(_out, it.second);
streamExpressionClass(_out, it.second);
}
_out << "Equivalence classes: " << endl;
for (EquivalenceClassId eqClass = 0; eqClass < m_equivalenceClasses.size(); ++eqClass)
streamEquivalenceClass(_out, eqClass);
for (ExpressionClasses::Id eqClass = 0; eqClass < m_expressionClasses.size(); ++eqClass)
streamExpressionClass(_out, eqClass);
_out << "Current stack: " << endl;
for (auto const& it: _currentStack)
{
_out << " " << dec << it.first << ": ";
streamEquivalenceClass(_out, it.second);
streamExpressionClass(_out, it.second);
}
_out << "Target stack: " << endl;
for (auto const& it: _targetStack)
{
_out << " " << dec << it.first << ": ";
streamEquivalenceClass(_out, it.second);
streamExpressionClass(_out, it.second);
}
return _out;
@ -103,7 +103,7 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item)
{
if (_item.deposit() != 1)
BOOST_THROW_EXCEPTION(InvalidDeposit());
setStackElement(++m_stackHeight, getClass(_item, {}));
setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}));
}
else
{
@ -121,16 +121,16 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item)
);
else if (instruction != Instruction::POP)
{
vector<EquivalenceClassId> arguments(info.args);
vector<ExpressionClasses::Id> arguments(info.args);
for (int i = 0; i < info.args; ++i)
arguments[i] = getStackElement(m_stackHeight - i);
setStackElement(m_stackHeight + _item.deposit(), getClass(_item, arguments));
setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments));
}
m_stackHeight += _item.deposit();
}
}
void CommonSubexpressionEliminator::setStackElement(int _stackHeight, EquivalenceClassId _class)
void CommonSubexpressionEliminator::setStackElement(int _stackHeight, ExpressionClasses::Id _class)
{
unsigned nextSequence = getNextStackElementSequence(_stackHeight);
m_stackElements[make_pair(_stackHeight, nextSequence)] = _class;
@ -140,8 +140,8 @@ void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _st
{
if (_stackHeightA == _stackHeightB)
BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Swap on same stack elements."));
EquivalenceClassId classA = getStackElement(_stackHeightA);
EquivalenceClassId classB = getStackElement(_stackHeightB);
ExpressionClasses::Id classA = getStackElement(_stackHeightA);
ExpressionClasses::Id classB = getStackElement(_stackHeightB);
unsigned nextSequenceA = getNextStackElementSequence(_stackHeightA);
unsigned nextSequenceB = getNextStackElementSequence(_stackHeightB);
@ -149,7 +149,7 @@ void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _st
m_stackElements[make_pair(_stackHeightB, nextSequenceB)] = classA;
}
EquivalenceClassId CommonSubexpressionEliminator::getStackElement(int _stackHeight)
ExpressionClasses::Id CommonSubexpressionEliminator::getStackElement(int _stackHeight)
{
// retrieve class by last sequence number
unsigned nextSequence = getNextStackElementSequence(_stackHeight);
@ -162,86 +162,8 @@ EquivalenceClassId CommonSubexpressionEliminator::getStackElement(int _stackHeig
if (_stackHeight <= -16)
BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Stack too deep."));
// This is a special assembly item that refers to elements pre-existing on the initial stack.
m_spareAssemblyItem.push_back(make_shared<AssemblyItem>(dupInstruction(1 - _stackHeight)));
m_equivalenceClasses.push_back(make_pair(m_spareAssemblyItem.back().get(), EquivalenceClassIds()));
return m_stackElements[make_pair(_stackHeight, nextSequence)] = EquivalenceClassId(m_equivalenceClasses.size() - 1);
}
EquivalenceClassId CommonSubexpressionEliminator::getClass(
const AssemblyItem& _item,
EquivalenceClassIds const& _arguments
)
{
// TODO: do a clever search, i.e.
// - check for the presence of constants in the argument classes and do arithmetic
// - check whether the two items are equal for a SUB instruction
// - check whether 0 or 1 is in one of the classes for a MUL
EquivalenceClassIds args = _arguments;
if (SemanticInformation::isCommutativeOperation(_item))
sort(args.begin(), args.end());
//@todo use a better data structure for search here
for (EquivalenceClassId c = 0; c < m_equivalenceClasses.size(); ++c)
{
AssemblyItem const& classItem = *m_equivalenceClasses.at(c).first;
if (classItem != _item)
continue;
assertThrow(
args.size() == m_equivalenceClasses.at(c).second.size(),
OptimizerException,
"Equal assembly items with different number of arguments."
);
if (equal(args.begin(), args.end(), m_equivalenceClasses.at(c).second.begin()))
return c;
}
// constant folding
if (_item.type() == Operation && args.size() == 2 && all_of(
args.begin(),
args.end(),
[this](EquivalenceClassId eqc) { return m_equivalenceClasses.at(eqc).first->match(Push); }))
{
auto signextend = [](u256 const& _a, u256 const& _b) -> u256
{
if (_a >= 31)
return _b;
unsigned testBit = unsigned(_a) * 8 + 7;
u256 mask = (u256(1) << testBit) - 1;
return boost::multiprecision::bit_test(_b, testBit) ? _b | ~mask : _b & mask;
};
map<Instruction, function<u256(u256 const&, u256 const&)>> const arithmetics =
{
{ Instruction::SUB, [](u256 const& _a, u256 const& _b) -> u256 {return _a - _b; } },
{ Instruction::DIV, [](u256 const& _a, u256 const& _b) -> u256 {return _b == 0 ? 0 : _a / _b; } },
{ Instruction::SDIV, [](u256 const& _a, u256 const& _b) -> u256 { return _b == 0 ? 0 : s2u(u2s(_a) / u2s(_b)); } },
{ Instruction::MOD, [](u256 const& _a, u256 const& _b) -> u256 { return _b == 0 ? 0 : _a % _b; } },
{ Instruction::SMOD, [](u256 const& _a, u256 const& _b) -> u256 { return _b == 0 ? 0 : s2u(u2s(_a) % u2s(_b)); } },
{ Instruction::EXP, [](u256 const& _a, u256 const& _b) -> u256 { return (u256)boost::multiprecision::powm(bigint(_a), bigint(_b), bigint(1) << 256); } },
{ Instruction::SIGNEXTEND, signextend },
{ Instruction::LT, [](u256 const& _a, u256 const& _b) -> u256 { return _a < _b ? 1 : 0; } },
{ Instruction::GT, [](u256 const& _a, u256 const& _b) -> u256 { return _a > _b ? 1 : 0; } },
{ Instruction::SLT, [](u256 const& _a, u256 const& _b) -> u256 { return u2s(_a) < u2s(_b) ? 1 : 0; } },
{ Instruction::SGT, [](u256 const& _a, u256 const& _b) -> u256 { return u2s(_a) > u2s(_b) ? 1 : 0; } },
{ Instruction::EQ, [](u256 const& _a, u256 const& _b) -> u256 { return _a == _b ? 1 : 0; } },
{ Instruction::ADD, [](u256 const& _a, u256 const& _b) -> u256 { return _a + _b; } },
{ Instruction::MUL, [](u256 const& _a, u256 const& _b) -> u256 { return _a * _b; } },
{ Instruction::AND, [](u256 const& _a, u256 const& _b) -> u256 { return _a & _b; } },
{ Instruction::OR, [](u256 const& _a, u256 const& _b) -> u256 { return _a | _b; } },
{ Instruction::XOR, [](u256 const& _a, u256 const& _b) -> u256 { return _a ^ _b; } },
};
if (arithmetics.count(_item.instruction()))
{
u256 result = arithmetics.at(_item.instruction())(
m_equivalenceClasses.at(args[0]).first->data(),
m_equivalenceClasses.at(args[1]).first->data()
);
m_spareAssemblyItem.push_back(make_shared<AssemblyItem>(result));
return getClass(*m_spareAssemblyItem.back());
}
}
m_equivalenceClasses.push_back(make_pair(&_item, args));
return m_equivalenceClasses.size() - 1;
return m_stackElements[make_pair(_stackHeight, nextSequence)] =
m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight)));
}
unsigned CommonSubexpressionEliminator::getNextStackElementSequence(int _stackHeight)
@ -318,15 +240,11 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
}
AssemblyItems CSECodeGenerator::generateCode(
map<int, EquivalenceClassId> const& _initialStack,
map<int, EquivalenceClassId> const& _targetStackContents,
vector<pair<AssemblyItem const*, EquivalenceClassIds>> const& _equivalenceClasses
map<int, ExpressionClasses::Id> const& _initialStack,
map<int, ExpressionClasses::Id> const& _targetStackContents
)
{
// reset
*this = move(CSECodeGenerator());
m_stack = _initialStack;
m_equivalenceClasses = _equivalenceClasses;
for (auto const& item: m_stack)
if (!m_classPositions.count(item.second))
m_classPositions[item.second] = item.first;
@ -377,18 +295,18 @@ AssemblyItems CSECodeGenerator::generateCode(
return m_generatedItems;
}
void CSECodeGenerator::addDependencies(EquivalenceClassId _c)
void CSECodeGenerator::addDependencies(ExpressionClasses::Id _c)
{
if (m_neededBy.count(_c))
return;
for (EquivalenceClassId argument: m_equivalenceClasses.at(_c).second)
for (ExpressionClasses::Id argument: m_expressionClasses.representative(_c).arguments)
{
addDependencies(argument);
m_neededBy.insert(make_pair(argument, _c));
}
}
int CSECodeGenerator::generateClassElement(EquivalenceClassId _c)
int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c)
{
if (m_classPositions.count(_c))
{
@ -399,8 +317,8 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c)
);
return m_classPositions[_c];
}
EquivalenceClassIds const& arguments = m_equivalenceClasses.at(_c).second;
for (EquivalenceClassId arg: boost::adaptors::reverse(arguments))
ExpressionClasses::Ids const& arguments = m_expressionClasses.representative(_c).arguments;
for (ExpressionClasses::Id arg: boost::adaptors::reverse(arguments))
generateClassElement(arg);
// The arguments are somewhere on the stack now, so it remains to move them at the correct place.
@ -458,7 +376,7 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c)
for (size_t i = 0; i < arguments.size(); ++i)
assertThrow(m_stack[m_stackHeight - i] == arguments[i], OptimizerException, "Expected arguments not present." );
AssemblyItem const& item = *m_equivalenceClasses.at(_c).first;
AssemblyItem const& item = *m_expressionClasses.representative(_c).item;
while (SemanticInformation::isCommutativeOperation(item) &&
!m_generatedItems.empty() &&
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1))
@ -469,12 +387,12 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c)
m_classPositions[arg] = c_invalidPosition;
for (size_t i = 0; i < arguments.size(); ++i)
m_stack.erase(m_stackHeight - i);
appendItem(*m_equivalenceClasses.at(_c).first);
appendItem(*m_expressionClasses.representative(_c).item);
m_stack[m_stackHeight] = _c;
return m_classPositions[_c] = m_stackHeight;
}
bool CSECodeGenerator::canBeRemoved(EquivalenceClassId _element, EquivalenceClassId _result)
bool CSECodeGenerator::canBeRemoved(ExpressionClasses::Id _element, ExpressionClasses::Id _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.
@ -493,7 +411,7 @@ bool CSECodeGenerator::removeStackTopIfPossible()
if (m_stack.empty())
return false;
assertThrow(m_stack.count(m_stackHeight), OptimizerException, "");
EquivalenceClassId top = m_stack[m_stackHeight];
ExpressionClasses::Id top = m_stack[m_stackHeight];
if (!canBeRemoved(top))
return false;
m_generatedItems.push_back(AssemblyItem(Instruction::POP));

52
libevmcore/CommonSubexpressionEliminator.h

@ -28,6 +28,7 @@
#include <ostream>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Exceptions.h>
#include <libevmcore/ExpressionClasses.h>
namespace dev
{
@ -37,9 +38,6 @@ namespace eth
class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
using EquivalenceClassId = unsigned;
using EquivalenceClassIds = std::vector<EquivalenceClassId>;
/**
* Optimizer step that performs common subexpression elimination and stack reorganisation,
* i.e. it tries to infer equality among expressions and compute the values of two expressions
@ -67,24 +65,22 @@ public:
/// Streams debugging information to @a _out.
std::ostream& stream(
std::ostream& _out,
std::map<int, EquivalenceClassId> _currentStack = std::map<int, EquivalenceClassId>(),
std::map<int, EquivalenceClassId> _targetStack = std::map<int, EquivalenceClassId>()
std::map<int, ExpressionClasses::Id> _currentStack = std::map<int, ExpressionClasses::Id>(),
std::map<int, ExpressionClasses::Id> _targetStack = std::map<int, ExpressionClasses::Id>()
) const;
private:
/// Feeds the item into the system for analysis.
void feedItem(AssemblyItem const& _item);
/// Simplifies the given item using
/// Assigns a new equivalence class to the next sequence number of the given stack element.
void setStackElement(int _stackHeight, EquivalenceClassId _class);
void setStackElement(int _stackHeight, ExpressionClasses::Id _class);
/// Swaps the given stack elements in their next sequence number.
void swapStackElements(int _stackHeightA, int _stackHeightB);
/// Retrieves the current equivalence class fo the given stack element (or generates a new
/// one if it does not exist yet).
EquivalenceClassId getStackElement(int _stackHeight);
/// Retrieves the equivalence class resulting from the given item applied to the given classes,
/// might also create a new one.
EquivalenceClassId getClass(AssemblyItem const& _item, EquivalenceClassIds const& _arguments = {});
ExpressionClasses::Id getStackElement(int _stackHeight);
/// @returns the next sequence number of the given stack element.
unsigned getNextStackElementSequence(int _stackHeight);
@ -92,12 +88,9 @@ private:
/// Current stack height, can be negative.
int m_stackHeight = 0;
/// Mapping (stack height, sequence number) -> equivalence class
std::map<std::pair<int, unsigned>, EquivalenceClassId> m_stackElements;
/// Vector of equivalence class representatives - we only store one item of an equivalence
/// class and the index is used as identifier.
std::vector<std::pair<AssemblyItem const*, EquivalenceClassIds>> m_equivalenceClasses;
/// List of items generated during analysis.
std::vector<std::shared_ptr<AssemblyItem>> m_spareAssemblyItem;
std::map<std::pair<int, unsigned>, ExpressionClasses::Id> m_stackElements;
/// Structure containing the classes of equivalent expressions.
ExpressionClasses m_expressionClasses;
};
/**
@ -121,27 +114,30 @@ struct SemanticInformation
class CSECodeGenerator
{
public:
CSECodeGenerator(ExpressionClasses const& _expressionClasses):
m_expressionClasses(_expressionClasses)
{}
/// @returns the assembly items generated from the given requirements
/// @param _initialStack 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
/// @note resuts the state of the object for each call.
/// @note should only be called once on each object.
AssemblyItems generateCode(
std::map<int, EquivalenceClassId> const& _initialStack,
std::map<int, EquivalenceClassId> const& _targetStackContents,
std::vector<std::pair<AssemblyItem const*, EquivalenceClassIds>> const& _equivalenceClasses
std::map<int, ExpressionClasses::Id> const& _initialStack,
std::map<int, ExpressionClasses::Id> const& _targetStackContents
);
private:
/// Recursively discovers all dependencies to @a m_requests.
void addDependencies(EquivalenceClassId _c);
void addDependencies(ExpressionClasses::Id _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);
int generateClassElement(ExpressionClasses::Id _c);
/// @returns true if @a _element can be removed - in general or, if given, while computing @a _result.
bool canBeRemoved(EquivalenceClassId _element, EquivalenceClassId _result = EquivalenceClassId(-1));
bool canBeRemoved(ExpressionClasses::Id _element, ExpressionClasses::Id _result = ExpressionClasses::Id(-1));
/// Appends code to remove the topmost stack element if it can be removed.
bool removeStackTopIfPossible();
@ -160,16 +156,16 @@ private:
/// 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;
std::multimap<ExpressionClasses::Id, ExpressionClasses::Id> m_neededBy;
/// Current content of the stack.
std::map<int, EquivalenceClassId> m_stack;
std::map<int, ExpressionClasses::Id> m_stack;
/// Current positions of equivalence classes, equal to c_invalidPosition if already deleted.
std::map<EquivalenceClassId, int> m_classPositions;
std::map<ExpressionClasses::Id, int> m_classPositions;
/// The actual eqivalence class items and how to compute them.
std::vector<std::pair<AssemblyItem const*, EquivalenceClassIds>> m_equivalenceClasses;
ExpressionClasses const& m_expressionClasses;
/// The set of equivalence classes that should be present on the stack at the end.
std::set<EquivalenceClassId> m_finalClasses;
std::set<ExpressionClasses::Id> m_finalClasses;
};
template <class _AssemblyItemIterator>

110
libevmcore/ExpressionClasses.cpp

@ -0,0 +1,110 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file ExpressionClasses.cpp
* @author Christian <c@ethdev.com>
* @date 2015
* Container for equivalence classes of expressions for use in common subexpression elimination.
*/
#include <libevmcore/ExpressionClasses.h>
#include <boost/range/adaptor/reversed.hpp>
#include <libevmcore/Assembly.h>
#include <libevmcore/CommonSubexpressionEliminator.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
ExpressionClasses::Id ExpressionClasses::find(AssemblyItem const& _item, Ids const& _arguments)
{
// TODO: do a clever search, i.e.
// - check for the presence of constants in the argument classes and do arithmetic
// - check whether the two items are equal for a SUB instruction
// - check whether 0 or 1 is in one of the classes for a MUL
Expression exp;
exp.item = &_item;
exp.arguments = _arguments;
if (SemanticInformation::isCommutativeOperation(_item))
sort(exp.arguments.begin(), exp.arguments.end());
//@todo use a data structure that allows better searches
for (Expression const& e: m_representatives)
if (std::tie(*e.item, e.arguments) == std::tie(*exp.item, exp.arguments))
return e.id;
if (SemanticInformation::isDupInstruction(_item))
{
// Special item that refers to values pre-existing on the stack
m_spareAssemblyItem.push_back(make_shared<AssemblyItem>(_item));
exp.item = m_spareAssemblyItem.back().get();
}
else if (_item.type() == Operation)
{
//@todo try to avoid having to do this multiple times by storing not only one representative of
// an equivalence class
// constant folding
auto isConstant = [this](Id eqc) { return representative(eqc).item->match(Push); };
if (exp.arguments.size() == 2 && all_of(exp.arguments.begin(), exp.arguments.end(), isConstant))
{
auto signextend = [](u256 a, u256 b) -> u256
{
if (a >= 31)
return b;
unsigned testBit = unsigned(a) * 8 + 7;
u256 mask = (u256(1) << testBit) - 1;
return boost::multiprecision::bit_test(b, testBit) ? b | ~mask : b & mask;
};
map<Instruction, function<u256(u256, u256)>> const arithmetics =
{
{ Instruction::SUB, [](u256 a, u256 b) -> u256 {return a - b; } },
{ Instruction::DIV, [](u256 a, u256 b) -> u256 {return b == 0 ? 0 : a / b; } },
{ Instruction::SDIV, [](u256 a, u256 b) -> u256 { return b == 0 ? 0 : s2u(u2s(a) / u2s(b)); } },
{ Instruction::MOD, [](u256 a, u256 b) -> u256 { return b == 0 ? 0 : a % b; } },
{ Instruction::SMOD, [](u256 a, u256 b) -> u256 { return b == 0 ? 0 : s2u(u2s(a) % u2s(b)); } },
{ Instruction::EXP, [](u256 a, u256 b) -> u256 { return (u256)boost::multiprecision::powm(bigint(a), bigint(b), bigint(1) << 256); } },
{ Instruction::SIGNEXTEND, signextend },
{ Instruction::LT, [](u256 a, u256 b) -> u256 { return a < b ? 1 : 0; } },
{ Instruction::GT, [](u256 a, u256 b) -> u256 { return a > b ? 1 : 0; } },
{ Instruction::SLT, [](u256 a, u256 b) -> u256 { return u2s(a) < u2s(b) ? 1 : 0; } },
{ Instruction::SGT, [](u256 a, u256 b) -> u256 { return u2s(a) > u2s(b) ? 1 : 0; } },
{ Instruction::EQ, [](u256 a, u256 b) -> u256 { return a == b ? 1 : 0; } },
{ Instruction::ADD, [](u256 a, u256 b) -> u256 { return a + b; } },
{ Instruction::MUL, [](u256 a, u256 b) -> u256 { return a * b; } },
{ Instruction::AND, [](u256 a, u256 b) -> u256 { return a & b; } },
{ Instruction::OR, [](u256 a, u256 b) -> u256 { return a | b; } },
{ Instruction::XOR, [](u256 a, u256 b) -> u256 { return a ^ b; } },
};
if (arithmetics.count(_item.instruction()))
{
u256 result = arithmetics.at(_item.instruction())(
representative(exp.arguments[0]).item->data(),
representative(exp.arguments[1]).item->data()
);
m_spareAssemblyItem.push_back(make_shared<AssemblyItem>(result));
return find(*m_spareAssemblyItem.back());
}
}
}
exp.id = m_representatives.size();
m_representatives.push_back(exp);
return exp.id;
}

70
libevmcore/ExpressionClasses.h

@ -0,0 +1,70 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file ExpressionClasses.h
* @author Christian <c@ethdev.com>
* @date 2015
* Container for equivalence classes of expressions for use in common subexpression elimination.
*/
#pragma once
#include <vector>
#include <set>
#include <memory>
namespace dev
{
namespace eth
{
class AssemblyItem;
/**
* Collection of classes of equivalent expressions that can also determine the class of an expression.
* Identifiers are contiguously assigned to new classes starting from zero.
*/
class ExpressionClasses
{
public:
using Id = unsigned;
using Ids = std::vector<Id>;
struct Expression
{
Id id;
AssemblyItem const* item;
Ids arguments;
};
/// Retrieves the id of the expression equivalence class resulting from the given item applied to the
/// given classes, might also create a new one.
Id find(AssemblyItem const& _item, Ids const& _arguments = {});
/// @returns the canonical representative of an expression class.
Expression const& representative(Id _id) const { return m_representatives.at(_id); }
/// @returns the number of classes.
Id size() const { return m_representatives.size(); }
private:
/// Expression equivalence class representatives - we only store one item of an equivalence.
std::vector<Expression> m_representatives;
std::vector<std::shared_ptr<AssemblyItem>> m_spareAssemblyItem;
};
}
}
Loading…
Cancel
Save