Browse Source

Optimize breaking item.

cl-refactor
chriseth 10 years ago
parent
commit
b1ea943975
  1. 15
      libevmcore/Assembly.cpp
  2. 39
      libevmcore/CommonSubexpressionEliminator.cpp
  3. 11
      libevmcore/CommonSubexpressionEliminator.h
  4. 32
      test/SolidityOptimizer.cpp

15
libevmcore/Assembly.cpp

@ -187,18 +187,7 @@ Assembly& Assembly::optimise(bool _enable)
{ {
if (!_enable) if (!_enable)
return *this; return *this;
std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules = std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules;
{
{ { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { PushProgramSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
{ { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } },
{ { Instruction::ISZERO, Instruction::ISZERO }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } },
};
// jump to next instruction // jump to next instruction
rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }}); rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }});
@ -235,8 +224,6 @@ Assembly& Assembly::optimise(bool _enable)
*orig = move(*moveIter); *orig = move(*moveIter);
iter = m_items.erase(orig, iter); iter = m_items.erase(orig, iter);
} }
if (iter != m_items.end())
++iter;
} }
for (unsigned i = 0; i < m_items.size(); ++i) for (unsigned i = 0; i < m_items.size(); ++i)

39
libevmcore/CommonSubexpressionEliminator.cpp

@ -32,6 +32,8 @@ using namespace dev::eth;
vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems() vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
{ {
optimizeBreakingItem();
map<int, ExpressionClasses::Id> initialStackContents; map<int, ExpressionClasses::Id> initialStackContents;
map<int, ExpressionClasses::Id> targetStackContents; map<int, ExpressionClasses::Id> targetStackContents;
int minHeight = m_stackHeight + 1; int minHeight = m_stackHeight + 1;
@ -45,10 +47,13 @@ vector<AssemblyItem> CommonSubexpressionEliminator::getOptimizedItems()
// Debug info: // Debug info:
//stream(cout, initialStackContents, targetStackContents); //stream(cout, initialStackContents, targetStackContents);
return CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode( AssemblyItems items = CSECodeGenerator(m_expressionClasses, m_storeOperations).generateCode(
initialStackContents, initialStackContents,
targetStackContents targetStackContents
); );
if (m_breakingItem)
items.push_back(*m_breakingItem);
return items;
} }
ostream& CommonSubexpressionEliminator::stream( ostream& CommonSubexpressionEliminator::stream(
@ -91,12 +96,12 @@ ostream& CommonSubexpressionEliminator::stream(
return _out; return _out;
} }
void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item) void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _copyItem)
{ {
if (_item.type() != Operation) if (_item.type() != Operation)
{ {
assertThrow(_item.deposit() == 1, InvalidDeposit, ""); assertThrow(_item.deposit() == 1, InvalidDeposit, "");
setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, false)); setStackElement(++m_stackHeight, m_expressionClasses.find(_item, {}, _copyItem));
} }
else else
{ {
@ -126,12 +131,38 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item)
else if (_item.instruction() == Instruction::MLOAD) else if (_item.instruction() == Instruction::MLOAD)
setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0])); setStackElement(m_stackHeight + _item.deposit(), loadFromMemory(arguments[0]));
else else
setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, false)); setStackElement(m_stackHeight + _item.deposit(), m_expressionClasses.find(_item, arguments, _copyItem));
} }
m_stackHeight += _item.deposit(); m_stackHeight += _item.deposit();
} }
} }
void CommonSubexpressionEliminator::optimizeBreakingItem()
{
if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI))
return;
using Id = ExpressionClasses::Id;
static AssemblyItem s_jump = Instruction::JUMP;
Id condition = stackElement(m_stackHeight - 1);
Id zero = m_expressionClasses.find(u256(0));
if (m_expressionClasses.knownToBeDifferent(condition, zero))
{
feedItem(Instruction::SWAP1, true);
feedItem(Instruction::POP, true);
m_breakingItem = &s_jump;
return;
}
Id negatedCondition = m_expressionClasses.find(Instruction::ISZERO, {condition});
if (m_expressionClasses.knownToBeDifferent(negatedCondition, zero))
{
feedItem(Instruction::POP, true);
feedItem(Instruction::POP, true);
m_breakingItem = nullptr;
}
}
void CommonSubexpressionEliminator::setStackElement(int _stackHeight, ExpressionClasses::Id _class) void CommonSubexpressionEliminator::setStackElement(int _stackHeight, ExpressionClasses::Id _class)
{ {
m_stackElements[_stackHeight] = _class; m_stackElements[_stackHeight] = _class;

11
libevmcore/CommonSubexpressionEliminator.h

@ -88,7 +88,10 @@ public:
private: private:
/// Feeds the item into the system for analysis. /// Feeds the item into the system for analysis.
void feedItem(AssemblyItem const& _item); void feedItem(AssemblyItem const& _item, bool _copyItem = false);
/// Tries to optimize the item that breaks the basic block at the end.
void optimizeBreakingItem();
/// Simplifies the given item using /// Simplifies the given item using
/// Assigns a new equivalence class to the next sequence number of the given stack element. /// Assigns a new equivalence class to the next sequence number of the given stack element.
@ -130,6 +133,10 @@ private:
std::vector<StoreOperation> m_storeOperations; std::vector<StoreOperation> m_storeOperations;
/// Structure containing the classes of equivalent expressions. /// Structure containing the classes of equivalent expressions.
ExpressionClasses m_expressionClasses; ExpressionClasses m_expressionClasses;
/// The item that breaks the basic block, can be nullptr.
/// It is usually appended to the block but can be optimized in some cases.
AssemblyItem const* m_breakingItem = nullptr;
}; };
/** /**
@ -225,6 +232,8 @@ _AssemblyItemIterator CommonSubexpressionEliminator::feedItems(
{ {
for (; _iterator != _end && !SemanticInformation::breaksBasicBlock(*_iterator); ++_iterator) for (; _iterator != _end && !SemanticInformation::breaksBasicBlock(*_iterator); ++_iterator)
feedItem(*_iterator); feedItem(*_iterator);
if (_iterator != _end)
m_breakingItem = &(*_iterator++);
return _iterator; return _iterator;
} }

32
test/SolidityOptimizer.cpp

@ -536,6 +536,38 @@ BOOST_AUTO_TEST_CASE(cse_deep_stack)
}); });
} }
BOOST_AUTO_TEST_CASE(cse_jumpi_no_jump)
{
AssemblyItems input{
u256(0),
u256(1),
Instruction::DUP2,
AssemblyItem(PushTag, 1),
Instruction::JUMPI
};
checkCSE(input, {
u256(0),
u256(1)
});
}
BOOST_AUTO_TEST_CASE(cse_jumpi_jump)
{
AssemblyItems input{
u256(1),
u256(1),
Instruction::DUP2,
AssemblyItem(PushTag, 1),
Instruction::JUMPI
};
checkCSE(input, {
u256(1),
Instruction::DUP1,
AssemblyItem(PushTag, 1),
Instruction::JUMP
});
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save