|
@ -32,39 +32,34 @@ using namespace dev::eth; |
|
|
|
|
|
|
|
|
vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems() |
|
|
vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems() |
|
|
{ |
|
|
{ |
|
|
map<int, EquivalenceClassId> initialStackContents; |
|
|
map<int, ExpressionClasses::Id> initialStackContents; |
|
|
map<int, EquivalenceClassId> targetStackContents; |
|
|
map<int, ExpressionClasses::Id> targetStackContents; |
|
|
int minHeight = m_stackHeight + 1; |
|
|
int minHeight = m_stackHeight + 1; |
|
|
if (!m_stackElements.empty()) |
|
|
if (!m_stackElements.empty()) |
|
|
minHeight = min(minHeight, m_stackElements.begin()->first.first); |
|
|
minHeight = min(minHeight, m_stackElements.begin()->first); |
|
|
for (int height = minHeight; height <= max(0, m_stackHeight); ++height) |
|
|
for (int height = minHeight; height <= 0; ++height) |
|
|
{ |
|
|
initialStackContents[height] = initialStackElement(height); |
|
|
// make sure it is created
|
|
|
for (int height = minHeight; height <= m_stackHeight; ++height) |
|
|
EquivalenceClassId c = getStackElement(height); |
|
|
targetStackContents[height] = stackElement(height); |
|
|
if (height <= 0) |
|
|
|
|
|
initialStackContents[height] = getClass(AssemblyItem(dupInstruction(1 - height))); |
|
|
|
|
|
if (height <= m_stackHeight) |
|
|
|
|
|
targetStackContents[height] = c; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Debug info:
|
|
|
// Debug info:
|
|
|
//stream(cout, currentStackContents, targetStackContents);
|
|
|
//stream(cout, initialStackContents, targetStackContents);
|
|
|
|
|
|
|
|
|
return CSECodeGenerator().generateCode(initialStackContents, targetStackContents, m_equivalenceClasses); |
|
|
return CSECodeGenerator(m_expressionClasses).generateCode(initialStackContents, targetStackContents); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ostream& CommonSubexpressionEliminator::stream( |
|
|
ostream& CommonSubexpressionEliminator::stream( |
|
|
ostream& _out, |
|
|
ostream& _out, |
|
|
map<int, EquivalenceClassId> _currentStack, |
|
|
map<int, ExpressionClasses::Id> _currentStack, |
|
|
map<int, EquivalenceClassId> _targetStack |
|
|
map<int, ExpressionClasses::Id> _targetStack |
|
|
) const |
|
|
) const |
|
|
{ |
|
|
{ |
|
|
auto streamEquivalenceClass = [this](ostream& _out, EquivalenceClassId _id) |
|
|
auto streamExpressionClass = [this](ostream& _out, ExpressionClasses::Id _id) |
|
|
{ |
|
|
{ |
|
|
auto const& eqClass = m_equivalenceClasses.at(_id); |
|
|
auto const& expr = m_expressionClasses.representative(_id); |
|
|
_out << " " << _id << ": " << *eqClass.first; |
|
|
_out << " " << _id << ": " << *expr.item; |
|
|
_out << "("; |
|
|
_out << "("; |
|
|
for (EquivalenceClassId arg: eqClass.second) |
|
|
for (ExpressionClasses::Id arg: expr.arguments) |
|
|
_out << dec << arg << ","; |
|
|
_out << dec << arg << ","; |
|
|
_out << ")" << endl; |
|
|
_out << ")" << endl; |
|
|
}; |
|
|
}; |
|
@ -74,24 +69,24 @@ ostream& CommonSubexpressionEliminator::stream( |
|
|
_out << "Stack elements: " << endl; |
|
|
_out << "Stack elements: " << endl; |
|
|
for (auto const& it: m_stackElements) |
|
|
for (auto const& it: m_stackElements) |
|
|
{ |
|
|
{ |
|
|
_out << " " << dec << it.first.first << "(" << it.first.second << ") = "; |
|
|
_out << " " << dec << it.first << " = "; |
|
|
streamEquivalenceClass(_out, it.second); |
|
|
streamExpressionClass(_out, it.second); |
|
|
} |
|
|
} |
|
|
_out << "Equivalence classes: " << endl; |
|
|
_out << "Equivalence classes: " << endl; |
|
|
for (EquivalenceClassId eqClass = 0; eqClass < m_equivalenceClasses.size(); ++eqClass) |
|
|
for (ExpressionClasses::Id eqClass = 0; eqClass < m_expressionClasses.size(); ++eqClass) |
|
|
streamEquivalenceClass(_out, eqClass); |
|
|
streamExpressionClass(_out, eqClass); |
|
|
|
|
|
|
|
|
_out << "Current stack: " << endl; |
|
|
_out << "Current stack: " << endl; |
|
|
for (auto const& it: _currentStack) |
|
|
for (auto const& it: _currentStack) |
|
|
{ |
|
|
{ |
|
|
_out << " " << dec << it.first << ": "; |
|
|
_out << " " << dec << it.first << ": "; |
|
|
streamEquivalenceClass(_out, it.second); |
|
|
streamExpressionClass(_out, it.second); |
|
|
} |
|
|
} |
|
|
_out << "Target stack: " << endl; |
|
|
_out << "Target stack: " << endl; |
|
|
for (auto const& it: _targetStack) |
|
|
for (auto const& it: _targetStack) |
|
|
{ |
|
|
{ |
|
|
_out << " " << dec << it.first << ": "; |
|
|
_out << " " << dec << it.first << ": "; |
|
|
streamEquivalenceClass(_out, it.second); |
|
|
streamExpressionClass(_out, it.second); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return _out; |
|
|
return _out; |
|
@ -103,7 +98,7 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) |
|
|
{ |
|
|
{ |
|
|
if (_item.deposit() != 1) |
|
|
if (_item.deposit() != 1) |
|
|
BOOST_THROW_EXCEPTION(InvalidDeposit()); |
|
|
BOOST_THROW_EXCEPTION(InvalidDeposit()); |
|
|
setStackElement(++m_stackHeight, getClass(_item, {})); |
|
|
setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {})); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
@ -112,7 +107,7 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) |
|
|
if (SemanticInformation::isDupInstruction(_item)) |
|
|
if (SemanticInformation::isDupInstruction(_item)) |
|
|
setStackElement( |
|
|
setStackElement( |
|
|
m_stackHeight + 1, |
|
|
m_stackHeight + 1, |
|
|
getStackElement(m_stackHeight - int(instruction) + int(Instruction::DUP1)) |
|
|
stackElement(m_stackHeight - int(instruction) + int(Instruction::DUP1)) |
|
|
); |
|
|
); |
|
|
else if (SemanticInformation::isSwapInstruction(_item)) |
|
|
else if (SemanticInformation::isSwapInstruction(_item)) |
|
|
swapStackElements( |
|
|
swapStackElements( |
|
@ -121,139 +116,45 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) |
|
|
); |
|
|
); |
|
|
else if (instruction != Instruction::POP) |
|
|
else if (instruction != Instruction::POP) |
|
|
{ |
|
|
{ |
|
|
vector<EquivalenceClassId> arguments(info.args); |
|
|
vector<ExpressionClasses::Id> arguments(info.args); |
|
|
for (int i = 0; i < info.args; ++i) |
|
|
for (int i = 0; i < info.args; ++i) |
|
|
arguments[i] = getStackElement(m_stackHeight - i); |
|
|
arguments[i] = stackElement(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(); |
|
|
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[_stackHeight] = _class; |
|
|
m_stackElements[make_pair(_stackHeight, nextSequence)] = _class; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _stackHeightB) |
|
|
void CommonSubexpressionEliminator::swapStackElements(int _stackHeightA, int _stackHeightB) |
|
|
{ |
|
|
{ |
|
|
if (_stackHeightA == _stackHeightB) |
|
|
if (_stackHeightA == _stackHeightB) |
|
|
BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Swap on same stack elements.")); |
|
|
BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Swap on same stack elements.")); |
|
|
EquivalenceClassId classA = getStackElement(_stackHeightA); |
|
|
// ensure they are created
|
|
|
EquivalenceClassId classB = getStackElement(_stackHeightB); |
|
|
stackElement(_stackHeightA); |
|
|
|
|
|
stackElement(_stackHeightB); |
|
|
|
|
|
|
|
|
unsigned nextSequenceA = getNextStackElementSequence(_stackHeightA); |
|
|
swap(m_stackElements[_stackHeightA], m_stackElements[_stackHeightB]); |
|
|
unsigned nextSequenceB = getNextStackElementSequence(_stackHeightB); |
|
|
|
|
|
m_stackElements[make_pair(_stackHeightA, nextSequenceA)] = classB; |
|
|
|
|
|
m_stackElements[make_pair(_stackHeightB, nextSequenceB)] = classA; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
EquivalenceClassId CommonSubexpressionEliminator::getStackElement(int _stackHeight) |
|
|
ExpressionClasses::Id CommonSubexpressionEliminator::stackElement(int _stackHeight) |
|
|
{ |
|
|
{ |
|
|
// retrieve class by last sequence number
|
|
|
if (m_stackElements.count(_stackHeight)) |
|
|
unsigned nextSequence = getNextStackElementSequence(_stackHeight); |
|
|
return m_stackElements.at(_stackHeight); |
|
|
if (nextSequence > 0) |
|
|
|
|
|
return m_stackElements[make_pair(_stackHeight, nextSequence - 1)]; |
|
|
|
|
|
|
|
|
|
|
|
// Stack element not found (not assigned yet), create new equivalence class.
|
|
|
// Stack element not found (not assigned yet), create new equivalence class.
|
|
|
if (_stackHeight > 0) |
|
|
return m_stackElements[_stackHeight] = initialStackElement(_stackHeight); |
|
|
BOOST_THROW_EXCEPTION(OptimizerException() << errinfo_comment("Stack element accessed before assignment.")); |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
unsigned CommonSubexpressionEliminator::getNextStackElementSequence(int _stackHeight) |
|
|
ExpressionClasses::Id CommonSubexpressionEliminator::initialStackElement(int _stackHeight) |
|
|
{ |
|
|
{ |
|
|
auto it = m_stackElements.upper_bound(make_pair(_stackHeight, unsigned(-1))); |
|
|
assertThrow(_stackHeight <= 0, OptimizerException, "Initial stack element of positive height requested."); |
|
|
if (it == m_stackElements.begin()) |
|
|
assertThrow(_stackHeight > -16, StackTooDeepException, ""); |
|
|
return 0; |
|
|
// This is a special assembly item that refers to elements pre-existing on the initial stack.
|
|
|
--it; |
|
|
return m_expressionClasses.find(AssemblyItem(dupInstruction(1 - _stackHeight))); |
|
|
if (it->first.first == _stackHeight) |
|
|
|
|
|
return it->first.second + 1; |
|
|
|
|
|
else |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) |
|
|
bool SemanticInformation::breaksBasicBlock(AssemblyItem const& _item) |
|
@ -318,15 +219,11 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
AssemblyItems CSECodeGenerator::generateCode( |
|
|
AssemblyItems CSECodeGenerator::generateCode( |
|
|
map<int, EquivalenceClassId> const& _initialStack, |
|
|
map<int, ExpressionClasses::Id> const& _initialStack, |
|
|
map<int, EquivalenceClassId> const& _targetStackContents, |
|
|
map<int, ExpressionClasses::Id> const& _targetStackContents |
|
|
vector<pair<AssemblyItem const*, EquivalenceClassIds>> const& _equivalenceClasses |
|
|
|
|
|
) |
|
|
) |
|
|
{ |
|
|
{ |
|
|
// reset
|
|
|
|
|
|
*this = move(CSECodeGenerator()); |
|
|
|
|
|
m_stack = _initialStack; |
|
|
m_stack = _initialStack; |
|
|
m_equivalenceClasses = _equivalenceClasses; |
|
|
|
|
|
for (auto const& item: m_stack) |
|
|
for (auto const& item: m_stack) |
|
|
if (!m_classPositions.count(item.second)) |
|
|
if (!m_classPositions.count(item.second)) |
|
|
m_classPositions[item.second] = item.first; |
|
|
m_classPositions[item.second] = item.first; |
|
@ -377,18 +274,18 @@ AssemblyItems CSECodeGenerator::generateCode( |
|
|
return m_generatedItems; |
|
|
return m_generatedItems; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void CSECodeGenerator::addDependencies(EquivalenceClassId _c) |
|
|
void CSECodeGenerator::addDependencies(ExpressionClasses::Id _c) |
|
|
{ |
|
|
{ |
|
|
if (m_neededBy.count(_c)) |
|
|
if (m_neededBy.count(_c)) |
|
|
return; |
|
|
return; |
|
|
for (EquivalenceClassId argument: m_equivalenceClasses.at(_c).second) |
|
|
for (ExpressionClasses::Id argument: m_expressionClasses.representative(_c).arguments) |
|
|
{ |
|
|
{ |
|
|
addDependencies(argument); |
|
|
addDependencies(argument); |
|
|
m_neededBy.insert(make_pair(argument, _c)); |
|
|
m_neededBy.insert(make_pair(argument, _c)); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int CSECodeGenerator::generateClassElement(EquivalenceClassId _c) |
|
|
int CSECodeGenerator::generateClassElement(ExpressionClasses::Id _c) |
|
|
{ |
|
|
{ |
|
|
if (m_classPositions.count(_c)) |
|
|
if (m_classPositions.count(_c)) |
|
|
{ |
|
|
{ |
|
@ -399,8 +296,8 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c) |
|
|
); |
|
|
); |
|
|
return m_classPositions[_c]; |
|
|
return m_classPositions[_c]; |
|
|
} |
|
|
} |
|
|
EquivalenceClassIds const& arguments = m_equivalenceClasses.at(_c).second; |
|
|
ExpressionClasses::Ids const& arguments = m_expressionClasses.representative(_c).arguments; |
|
|
for (EquivalenceClassId arg: boost::adaptors::reverse(arguments)) |
|
|
for (ExpressionClasses::Id arg: boost::adaptors::reverse(arguments)) |
|
|
generateClassElement(arg); |
|
|
generateClassElement(arg); |
|
|
|
|
|
|
|
|
// The arguments are somewhere on the stack now, so it remains to move them at the correct place.
|
|
|
// The arguments are somewhere on the stack now, so it remains to move them at the correct place.
|
|
@ -458,7 +355,7 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c) |
|
|
for (size_t i = 0; i < arguments.size(); ++i) |
|
|
for (size_t i = 0; i < arguments.size(); ++i) |
|
|
assertThrow(m_stack[m_stackHeight - i] == arguments[i], OptimizerException, "Expected arguments not present." ); |
|
|
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) && |
|
|
while (SemanticInformation::isCommutativeOperation(item) && |
|
|
!m_generatedItems.empty() && |
|
|
!m_generatedItems.empty() && |
|
|
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) |
|
|
m_generatedItems.back() == AssemblyItem(Instruction::SWAP1)) |
|
@ -469,12 +366,12 @@ int CSECodeGenerator::generateClassElement(EquivalenceClassId _c) |
|
|
m_classPositions[arg] = c_invalidPosition; |
|
|
m_classPositions[arg] = c_invalidPosition; |
|
|
for (size_t i = 0; i < arguments.size(); ++i) |
|
|
for (size_t i = 0; i < arguments.size(); ++i) |
|
|
m_stack.erase(m_stackHeight - i); |
|
|
m_stack.erase(m_stackHeight - i); |
|
|
appendItem(*m_equivalenceClasses.at(_c).first); |
|
|
appendItem(*m_expressionClasses.representative(_c).item); |
|
|
m_stack[m_stackHeight] = _c; |
|
|
m_stack[m_stackHeight] = _c; |
|
|
return m_classPositions[_c] = m_stackHeight; |
|
|
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
|
|
|
// 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.
|
|
|
// computed yet. Note that m_classPositions also includes classes that were deleted in the meantime.
|
|
@ -493,7 +390,7 @@ bool CSECodeGenerator::removeStackTopIfPossible() |
|
|
if (m_stack.empty()) |
|
|
if (m_stack.empty()) |
|
|
return false; |
|
|
return false; |
|
|
assertThrow(m_stack.count(m_stackHeight), OptimizerException, ""); |
|
|
assertThrow(m_stack.count(m_stackHeight), OptimizerException, ""); |
|
|
EquivalenceClassId top = m_stack[m_stackHeight]; |
|
|
ExpressionClasses::Id top = m_stack[m_stackHeight]; |
|
|
if (!canBeRemoved(top)) |
|
|
if (!canBeRemoved(top)) |
|
|
return false; |
|
|
return false; |
|
|
m_generatedItems.push_back(AssemblyItem(Instruction::POP)); |
|
|
m_generatedItems.push_back(AssemblyItem(Instruction::POP)); |
|
@ -505,7 +402,8 @@ bool CSECodeGenerator::removeStackTopIfPossible() |
|
|
void CSECodeGenerator::appendDup(int _fromPosition) |
|
|
void CSECodeGenerator::appendDup(int _fromPosition) |
|
|
{ |
|
|
{ |
|
|
int nr = 1 + m_stackHeight - _fromPosition; |
|
|
int nr = 1 + m_stackHeight - _fromPosition; |
|
|
assertThrow(1 <= nr && nr <= 16, OptimizerException, "Stack too deep."); |
|
|
assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); |
|
|
|
|
|
assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); |
|
|
m_generatedItems.push_back(AssemblyItem(dupInstruction(nr))); |
|
|
m_generatedItems.push_back(AssemblyItem(dupInstruction(nr))); |
|
|
m_stackHeight++; |
|
|
m_stackHeight++; |
|
|
m_stack[m_stackHeight] = m_stack[_fromPosition]; |
|
|
m_stack[m_stackHeight] = m_stack[_fromPosition]; |
|
@ -516,7 +414,8 @@ void CSECodeGenerator::appendSwapOrRemove(int _fromPosition) |
|
|
if (_fromPosition == m_stackHeight) |
|
|
if (_fromPosition == m_stackHeight) |
|
|
return; |
|
|
return; |
|
|
int nr = m_stackHeight - _fromPosition; |
|
|
int nr = m_stackHeight - _fromPosition; |
|
|
assertThrow(1 <= nr && nr <= 16, OptimizerException, "Stack too deep."); |
|
|
assertThrow(nr <= 16, StackTooDeepException, "Stack too deep."); |
|
|
|
|
|
assertThrow(1 <= nr, OptimizerException, "Invalid stack access."); |
|
|
m_generatedItems.push_back(AssemblyItem(swapInstruction(nr))); |
|
|
m_generatedItems.push_back(AssemblyItem(swapInstruction(nr))); |
|
|
// The value of a class can be present in multiple locations on the stack. We only update the
|
|
|
// 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
|
|
|
// "canonical" one that is tracked by m_classPositions
|
|
|