Disable deduplication to align with evmone validation.

This commit is contained in:
Daniel Kirchner 2023-01-04 16:59:54 +01:00
parent 0d7d0bfa78
commit 77567d32f4
11 changed files with 87 additions and 77 deletions

View File

@ -1046,7 +1046,7 @@ jobs:
name: Build evmone based on EOF branch name: Build evmone based on EOF branch
command: | command: |
( cd /usr/src; \ ( cd /usr/src; \
git clone --branch="eof-functions" --recurse-submodules https://github.com/ethereum/evmone.git; \ git clone --branch="eof" --recurse-submodules https://github.com/ethereum/evmone.git; \
cd evmone; \ cd evmone; \
sed -i -e 's/GNULIKE TRUE/GNULIKE FALSE/g' cmake/cable/CableCompilerSettings.cmake; \ sed -i -e 's/GNULIKE TRUE/GNULIKE FALSE/g' cmake/cable/CableCompilerSettings.cmake; \
mkdir build; \ mkdir build; \

View File

@ -408,7 +408,7 @@ map<u256, u256> const& Assembly::optimiseInternal(
} }
// This only modifies PushTags, we have to run again to actually remove code. // This only modifies PushTags, we have to run again to actually remove code.
if (_settings.runDeduplicate) if (_settings.runDeduplicate && !m_eofVersion.has_value())
for (auto& section: m_codeSections) for (auto& section: m_codeSections)
{ {
BlockDeduplicator deduplicator{section.items}; BlockDeduplicator deduplicator{section.items};
@ -500,6 +500,61 @@ map<u256, u256> const& Assembly::optimiseInternal(
return *m_tagReplacements; return *m_tagReplacements;
} }
namespace
{
uint16_t calcMaxStackHeight(vector<AssemblyItem> const& _items, uint16_t _args)
{
uint16_t maxStackHeight = 0;
std::stack<size_t> worklist;
std::vector<int32_t> stack_heights(_items.size(), -1);
stack_heights[0] = _args;
worklist.push(0u);
while (!worklist.empty())
{
size_t i = worklist.top();
worklist.pop();
AssemblyItem const& item = _items.at(i);
size_t stack_height_change = item.deposit();
ptrdiff_t stackHeight = stack_heights.at(i);
assertThrow(stackHeight != -1, AssemblyException, "");
std::vector<size_t> successors;
if (
item.type() != RelativeJump &&
!(item.type() == Operation && SemanticInformation::terminatesControlFlow(item.instruction())) &&
item.type() != RetF
)
{
assertThrow(i < _items.size() - 1, AssemblyException, "No terminating instruction.");
successors.emplace_back(i + 1);
}
if (item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
{
auto it = std::find(_items.begin(), _items.end(), item.tag());
assertThrow(it != _items.end(), AssemblyException, "Tag not found.");
successors.emplace_back(static_cast<size_t>(std::distance(_items.begin(), it)));
}
maxStackHeight = std::max(maxStackHeight, static_cast<uint16_t>(stackHeight + static_cast<ptrdiff_t>(item.maxStackHeightDelta())));
stackHeight += static_cast<ptrdiff_t>(stack_height_change);
for (size_t s: successors)
{
if (stack_heights.at(s) == -1)
{
stack_heights[s] = static_cast<int32_t>(stackHeight);
worklist.push(s);
}
else
assertThrow(stack_heights.at(s) == stackHeight, AssemblyException, "Stack height mismatch.");
}
}
return maxStackHeight;
}
}
LinkerObject const& Assembly::assemble() const LinkerObject const& Assembly::assemble() const
{ {
assertThrow(!m_invalid, AssemblyException, "Attempted to assemble invalid Assembly object."); assertThrow(!m_invalid, AssemblyException, "Attempted to assemble invalid Assembly object.");
@ -627,7 +682,7 @@ LinkerObject const& Assembly::assemble() const
{ {
ret.bytecode.push_back(codeSection.inputs); ret.bytecode.push_back(codeSection.inputs);
ret.bytecode.push_back(codeSection.outputs); ret.bytecode.push_back(codeSection.outputs);
appendBigEndianUint16(ret.bytecode, codeSection.maxStackHeight); appendBigEndianUint16(ret.bytecode, calcMaxStackHeight(codeSection.items, codeSection.inputs));
} }
} }

View File

@ -77,19 +77,14 @@ public:
AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
bytes const& data(util::h256 const& _i) const { return m_data.at(_i); } bytes const& data(util::h256 const& _i) const { return m_data.at(_i); }
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
uint16_t createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) uint16_t createFunction(uint8_t _args, uint8_t _rets)
{ {
size_t functionID = m_codeSections.size(); size_t functionID = m_codeSections.size();
assertThrow(functionID < 1024, AssemblyException, "Too many functions."); assertThrow(functionID < 1024, AssemblyException, "Too many functions.");
assertThrow(m_currentCodeSection == 0, AssemblyException, "Functions need to be declared from the main block."); assertThrow(m_currentCodeSection == 0, AssemblyException, "Functions need to be declared from the main block.");
m_codeSections.emplace_back(CodeSection{_args, _rets, _maxStackHeight, {}}); m_codeSections.emplace_back(CodeSection{_args, _rets, {}});
return static_cast<uint16_t>(functionID); return static_cast<uint16_t>(functionID);
} }
void setMaxStackHeight(uint16_t _functionID, uint16_t _maxStackHeight)
{
assertThrow(_functionID < m_codeSections.size(), AssemblyException, "Attempt to set the maximum stack height of an undeclared function.");
m_codeSections.at(_functionID).maxStackHeight = _maxStackHeight;
}
void beginFunction(uint16_t _functionID) void beginFunction(uint16_t _functionID)
{ {
assertThrow(m_currentCodeSection == 0, AssemblyException, "Atempted to begin a function before ending the last one."); assertThrow(m_currentCodeSection == 0, AssemblyException, "Atempted to begin a function before ending the last one.");
@ -214,7 +209,6 @@ public:
{ {
uint8_t inputs = 0; uint8_t inputs = 0;
uint8_t outputs = 0; uint8_t outputs = 0;
uint16_t maxStackHeight = 0;
AssemblyItems items{}; AssemblyItems items{};
}; };

View File

@ -116,6 +116,21 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag)
setData(data); setData(data);
} }
size_t AssemblyItem::maxStackHeightDelta() const
{
if (m_type == AssignImmutable)
{
assertThrow(m_immutableOccurrences.has_value(), util::Exception, "");
if (*m_immutableOccurrences == 0)
return 0;
else
return (*m_immutableOccurrences - 1) * 2 + 1;
}
else
return deposit();
}
size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision) const size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision) const
{ {
switch (m_type) switch (m_type)

View File

@ -187,6 +187,7 @@ public:
size_t arguments() const; size_t arguments() const;
size_t returnValues() const; size_t returnValues() const;
size_t deposit() const { return returnValues() - arguments(); } size_t deposit() const { return returnValues() - arguments(); }
size_t maxStackHeightDelta() const;
/// @returns true if the assembly item can be used in a functional context. /// @returns true if the assembly item can be used in a functional context.
bool canBeFunctional() const; bool canBeFunctional() const;

View File

@ -101,8 +101,7 @@ public:
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset. /// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") = 0; virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") = 0;
virtual FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) = 0; virtual FunctionID createFunction(uint8_t _args, uint8_t _rets) = 0;
virtual void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) = 0;
virtual void beginFunction(FunctionID _functionID) = 0; virtual void beginFunction(FunctionID _functionID) = 0;
virtual void endFunction() = 0; virtual void endFunction() = 0;

View File

@ -146,14 +146,9 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())}; return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
} }
AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackArgs) AbstractAssembly::FunctionID EthAssemblyAdapter::createFunction(uint8_t _args, uint8_t _rets)
{ {
return m_assembly.createFunction(_args, _rets, _maxStackArgs); return m_assembly.createFunction(_args, _rets);
}
void EthAssemblyAdapter::setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight)
{
m_assembly.setMaxStackHeight(_functionID, _maxStackHeight);
} }
void EthAssemblyAdapter::beginFunction(AbstractAssembly::FunctionID _functionID) void EthAssemblyAdapter::beginFunction(AbstractAssembly::FunctionID _functionID)

View File

@ -56,8 +56,7 @@ public:
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
void appendAssemblySize() override; void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = {}) override; std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = {}) override;
AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets, uint16_t _maxStackHeight) override; AbstractAssembly::FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
void setMaxStackHeight(FunctionID _functionID, uint16_t _maxStackHeight) override;
void beginFunction(AbstractAssembly::FunctionID _functionID) override; void beginFunction(AbstractAssembly::FunctionID _functionID) override;
void endFunction() override; void endFunction() override;
void appendFunctionCall(FunctionID _functionID) override; void appendFunctionCall(FunctionID _functionID) override;

View File

@ -104,7 +104,7 @@ pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::cr
return {}; return {};
} }
AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets, uint16_t) AbstractAssembly::FunctionID NoOutputAssembly::createFunction(uint8_t _args, uint8_t _rets)
{ {
yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max()); yulAssert(m_context->numFunctions <= std::numeric_limits<AbstractAssembly::FunctionID>::max());
AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++); AbstractAssembly::FunctionID id = static_cast<AbstractAssembly::FunctionID>(m_context->numFunctions++);

View File

@ -74,8 +74,7 @@ public:
void appendAssemblySize() override; void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") override; std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(bool _creation, std::optional<uint8_t> _eofVersion, std::string _name = "") override;
FunctionID createFunction(uint8_t _args, uint8_t rets, uint16_t _maxStackHeight) override; FunctionID createFunction(uint8_t _args, uint8_t _rets) override;
void setMaxStackHeight(AbstractAssembly::FunctionID, uint16_t) override {}
void beginFunction(FunctionID) override; void beginFunction(FunctionID) override;
void endFunction() override; void endFunction() override;
void appendFunctionCall(FunctionID _functionID) override; void appendFunctionCall(FunctionID _functionID) override;

View File

@ -40,55 +40,6 @@ using namespace solidity;
using namespace solidity::yul; using namespace solidity::yul;
using namespace std; using namespace std;
namespace
{
uint16_t getMaxStackHeight(CFG::BasicBlock const& _block, StackLayout const& _stackLayout)
{
size_t maxStackHeight = 0;
std::list<CFG::BasicBlock const*> toVisit;
std::set<CFG::BasicBlock const*> visited;
toVisit.push_back(&_block);
while (!toVisit.empty())
{
CFG::BasicBlock const* block = toVisit.back();
toVisit.pop_back();
if (!visited.insert(block).second)
continue;
auto& blockInfo = _stackLayout.blockInfos.at(block);
maxStackHeight = std::max(maxStackHeight, blockInfo.entryLayout.size());
for (auto const& operation: block->operations)
{
size_t entryLayout = _stackLayout.operationEntryLayout.at(&operation).size();
maxStackHeight = std::max(maxStackHeight, entryLayout);
size_t exitLayout = entryLayout - operation.input.size() + operation.output.size();
maxStackHeight = std::max(maxStackHeight, exitLayout);
}
maxStackHeight = std::max(maxStackHeight, blockInfo.exitLayout.size());
std::visit(util::GenericVisitor{
[&](CFG::BasicBlock::MainExit const&) {},
[&](CFG::BasicBlock::Jump const& _jump) { toVisit.emplace_back(_jump.target); },
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump)
{
toVisit.emplace_back(_conditionalJump.zero);
toVisit.emplace_back(_conditionalJump.nonZero);
},
[&](CFG::BasicBlock::FunctionReturn const&) {},
[&](CFG::BasicBlock::Terminated const&) {}
}, block->exit);
}
yulAssert(maxStackHeight <= 0xFFFF);
return static_cast<uint16_t>(maxStackHeight);
}
}
vector<StackTooDeepError> OptimizedEVMCodeTransform::run( vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
AbstractAssembly& _assembly, AbstractAssembly& _assembly,
AsmAnalysisInfo& _analysisInfo, AsmAnalysisInfo& _analysisInfo,
@ -105,7 +56,6 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
if (dfg->useFunctions) if (dfg->useFunctions)
{ {
_assembly.setMaxStackHeight(0, getMaxStackHeight(*dfg->entry, stackLayout));
for (Scope::Function const* function: dfg->functions) for (Scope::Function const* function: dfg->functions)
{ {
auto const& info = dfg->functionInfo.at(function); auto const& info = dfg->functionInfo.at(function);
@ -113,8 +63,7 @@ vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
yulAssert(info.returnVariables.size() <= 0xFF); yulAssert(info.returnVariables.size() <= 0xFF);
auto functionID = _assembly.createFunction( auto functionID = _assembly.createFunction(
static_cast<uint8_t>(info.parameters.size()), static_cast<uint8_t>(info.parameters.size()),
static_cast<uint8_t>(info.returnVariables.size()), static_cast<uint8_t>(info.returnVariables.size())
getMaxStackHeight(*info.entry, stackLayout)
); );
_builtinContext.functionIDs[function] = functionID; _builtinContext.functionIDs[function] = functionID;
} }
@ -162,7 +111,11 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
{ {
m_assembly.setSourceLocation(originLocationOf(_call)); m_assembly.setSourceLocation(originLocationOf(_call));
if (m_dfg.useFunctions) if (m_dfg.useFunctions)
{
m_assembly.appendFunctionCall(m_builtinContext.functionIDs.at(&_call.function.get())); m_assembly.appendFunctionCall(m_builtinContext.functionIDs.at(&_call.function.get()));
if (!_call.canContinue)
m_assembly.appendInstruction(evmasm::Instruction::INVALID);
}
else else
m_assembly.appendJumpTo( m_assembly.appendJumpTo(
getFunctionLabel(_call.function), getFunctionLabel(_call.function),