Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2022-03-16 15:41:37 +01:00
542 changed files with 6696 additions and 2399 deletions
+5 -6
View File
@@ -415,9 +415,8 @@ map<u256, u256> const& Assembly::optimiseInternal(
for (size_t subId = 0; subId < m_subs.size(); ++subId)
{
OptimiserSettings settings = _settings;
// Disable creation mode for sub-assemblies.
settings.isCreation = false;
map<u256, u256> const& subTagReplacements = m_subs[subId]->optimiseInternal(
Assembly& sub = *m_subs[subId];
map<u256, u256> const& subTagReplacements = sub.optimiseInternal(
settings,
JumpdestRemover::referencedTags(m_items, subId)
);
@@ -436,7 +435,7 @@ map<u256, u256> const& Assembly::optimiseInternal(
m_items,
_tagsReferencedFromOutside,
_settings.expectedExecutionsPerDeployment,
_settings.isCreation,
isCreation(),
_settings.evmVersion
}.optimise();
@@ -537,8 +536,8 @@ map<u256, u256> const& Assembly::optimiseInternal(
if (_settings.runConstantOptimiser)
ConstantOptimisationMethod::optimiseConstants(
_settings.isCreation,
_settings.isCreation ? 1 : _settings.expectedExecutionsPerDeployment,
isCreation(),
isCreation() ? 1 : _settings.expectedExecutionsPerDeployment,
_settings.evmVersion,
*this
);
+5 -2
View File
@@ -48,7 +48,7 @@ using AssemblyPointer = std::shared_ptr<Assembly>;
class Assembly
{
public:
explicit Assembly(std::string _name = std::string()):m_name(std::move(_name)) { }
Assembly(bool _creation, std::string _name): m_creation(_creation), m_name(std::move(_name)) { }
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); }
@@ -117,7 +117,6 @@ public:
struct OptimiserSettings
{
bool isCreation = false;
bool runInliner = false;
bool runJumpdestRemover = false;
bool runPeephole = false;
@@ -157,6 +156,8 @@ public:
std::vector<size_t> decodeSubPath(size_t _subObjectId) const;
size_t encodeSubPath(std::vector<size_t> const& _subPath);
bool isCreation() const { return m_creation; }
protected:
/// Does the same operations as @a optimise, but should only be applied to a sub and
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
@@ -214,6 +215,8 @@ protected:
mutable std::vector<size_t> m_tagPositionsInBytecode;
int m_deposit = 0;
/// True, if the assembly contains contract creation code.
bool const m_creation = false;
/// Internal name of the assembly object, only used with the Yul backend
/// currently
std::string m_name;
+1 -3
View File
@@ -200,9 +200,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const
case Operation:
{
assertThrow(isValidInstruction(instruction()), AssemblyException, "Invalid instruction.");
string name = instructionInfo(instruction()).name;
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
text = name;
text = util::toLower(instructionInfo(instruction()).name);
break;
}
case Push:
+3 -3
View File
@@ -219,7 +219,7 @@ void CSECodeGenerator::addDependencies(Id _c)
{
if (m_classPositions.count(_c))
return; // it is already on the stack
if (m_neededBy.count(_c))
if (m_neededBy.find(_c) != m_neededBy.end())
return; // we already computed the dependencies for _c
ExpressionClasses::Expression expr = m_expressionClasses.representative(_c);
assertThrow(expr.item, OptimizerException, "");
@@ -300,8 +300,8 @@ void CSECodeGenerator::addDependencies(Id _c)
void CSECodeGenerator::generateClassElement(Id _c, bool _allowSequenced)
{
for (auto it: m_classPositions)
for (auto p: it.second)
for (auto const& it: m_classPositions)
for (int p: it.second)
if (p > m_stackHeight)
{
assertThrow(false, OptimizerException, "");
+5 -4
View File
@@ -24,11 +24,12 @@
#pragma once
#include <vector>
#include <map>
#include <ostream>
#include <set>
#include <tuple>
#include <ostream>
#include <unordered_map>
#include <vector>
#include <libsolutil/CommonIO.h>
#include <libsolutil/Exceptions.h>
#include <libevmasm/ExpressionClasses.h>
@@ -154,11 +155,11 @@ 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<Id, Id> m_neededBy;
std::unordered_multimap<Id, Id> m_neededBy;
/// Current content of the stack.
std::map<int, Id> m_stack;
/// Current positions of equivalence classes, equal to the empty set if already deleted.
std::map<Id, std::set<int>> m_classPositions;
std::unordered_map<Id, std::set<int>> m_classPositions;
/// The actual equivalence class items and how to compute them.
ExpressionClasses& m_expressionClasses;
+115 -50
View File
@@ -41,51 +41,28 @@ struct OptimiserState
std::back_insert_iterator<AssemblyItems> out;
};
template <class Method, size_t Arguments>
struct ApplyRule
template<typename FunctionType>
struct FunctionParameterCount;
template<typename R, typename... Args>
struct FunctionParameterCount<R(Args...)>
{
};
template <class Method>
struct ApplyRule<Method, 4>
{
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
{
return Method::applySimple(_in[0], _in[1], _in[2], _in[3], _out);
}
};
template <class Method>
struct ApplyRule<Method, 3>
{
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
{
return Method::applySimple(_in[0], _in[1], _in[2], _out);
}
};
template <class Method>
struct ApplyRule<Method, 2>
{
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
{
return Method::applySimple(_in[0], _in[1], _out);
}
};
template <class Method>
struct ApplyRule<Method, 1>
{
static bool applyRule(AssemblyItems::const_iterator _in, std::back_insert_iterator<AssemblyItems> _out)
{
return Method::applySimple(_in[0], _out);
}
static constexpr auto value = sizeof...(Args);
};
template <class Method, size_t WindowSize>
template <class Method>
struct SimplePeepholeOptimizerMethod
{
template <size_t... Indices>
static bool applyRule(AssemblyItems::const_iterator _in, back_insert_iterator<AssemblyItems> _out, index_sequence<Indices...>)
{
return Method::applySimple(_in[Indices]..., _out);
}
static bool apply(OptimiserState& _state)
{
static constexpr size_t WindowSize = FunctionParameterCount<decltype(Method::applySimple)>::value - 1;
if (
_state.i + WindowSize <= _state.items.size() &&
ApplyRule<Method, WindowSize>::applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out)
applyRule(_state.items.begin() + static_cast<ptrdiff_t>(_state.i), _state.out, make_index_sequence<WindowSize>{})
)
{
_state.i += WindowSize;
@@ -96,7 +73,7 @@ struct SimplePeepholeOptimizerMethod
}
};
struct Identity: SimplePeepholeOptimizerMethod<Identity, 1>
struct Identity: SimplePeepholeOptimizerMethod<Identity>
{
static bool applySimple(AssemblyItem const& _item, std::back_insert_iterator<AssemblyItems> _out)
{
@@ -105,7 +82,7 @@ struct Identity: SimplePeepholeOptimizerMethod<Identity, 1>
}
};
struct PushPop: SimplePeepholeOptimizerMethod<PushPop, 2>
struct PushPop: SimplePeepholeOptimizerMethod<PushPop>
{
static bool applySimple(AssemblyItem const& _push, AssemblyItem const& _pop, std::back_insert_iterator<AssemblyItems>)
{
@@ -118,7 +95,7 @@ struct PushPop: SimplePeepholeOptimizerMethod<PushPop, 2>
}
};
struct OpPop: SimplePeepholeOptimizerMethod<OpPop, 2>
struct OpPop: SimplePeepholeOptimizerMethod<OpPop>
{
static bool applySimple(
AssemblyItem const& _op,
@@ -140,7 +117,36 @@ struct OpPop: SimplePeepholeOptimizerMethod<OpPop, 2>
}
};
struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap, 2>
struct OpStop: SimplePeepholeOptimizerMethod<OpStop>
{
static bool applySimple(
AssemblyItem const& _op,
AssemblyItem const& _stop,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (_stop == Instruction::STOP)
{
if (_op.type() == Operation)
{
Instruction instr = _op.instruction();
if (!instructionInfo(instr).sideEffects)
{
*_out = {Instruction::STOP, _op.location()};
return true;
}
}
else if (_op.type() == Push)
{
*_out = {Instruction::STOP, _op.location()};
return true;
}
}
return false;
}
};
struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap>
{
static size_t applySimple(AssemblyItem const& _s1, AssemblyItem const& _s2, std::back_insert_iterator<AssemblyItems>)
{
@@ -148,7 +154,7 @@ struct DoubleSwap: SimplePeepholeOptimizerMethod<DoubleSwap, 2>
}
};
struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush, 2>
struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush>
{
static bool applySimple(AssemblyItem const& _push1, AssemblyItem const& _push2, std::back_insert_iterator<AssemblyItems> _out)
{
@@ -163,7 +169,7 @@ struct DoublePush: SimplePeepholeOptimizerMethod<DoublePush, 2>
}
};
struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap, 2>
struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap>
{
static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out)
{
@@ -181,7 +187,7 @@ struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap, 2>
}
};
struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison, 2>
struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison>
{
static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out)
{
@@ -207,7 +213,7 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison, 2>
};
/// Remove swapN after dupN
struct DupSwap: SimplePeepholeOptimizerMethod<DupSwap, 2>
struct DupSwap: SimplePeepholeOptimizerMethod<DupSwap>
{
static size_t applySimple(
AssemblyItem const& _dupN,
@@ -230,7 +236,7 @@ struct DupSwap: SimplePeepholeOptimizerMethod<DupSwap, 2>
};
struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI, 4>
struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI>
{
static size_t applySimple(
AssemblyItem const& _iszero1,
@@ -256,7 +262,66 @@ struct IsZeroIsZeroJumpI: SimplePeepholeOptimizerMethod<IsZeroIsZeroJumpI, 4>
}
};
struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext, 3>
struct EqIsZeroJumpI: SimplePeepholeOptimizerMethod<EqIsZeroJumpI>
{
static size_t applySimple(
AssemblyItem const& _eq,
AssemblyItem const& _iszero,
AssemblyItem const& _pushTag,
AssemblyItem const& _jumpi,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_eq == Instruction::EQ &&
_iszero == Instruction::ISZERO &&
_pushTag.type() == PushTag &&
_jumpi == Instruction::JUMPI
)
{
*_out = AssemblyItem(Instruction::SUB, _eq.location());
*_out = _pushTag;
*_out = _jumpi;
return true;
}
else
return false;
}
};
// push_tag_1 jumpi push_tag_2 jump tag_1: -> iszero push_tag_2 jumpi tag_1:
struct DoubleJump: SimplePeepholeOptimizerMethod<DoubleJump>
{
static size_t applySimple(
AssemblyItem const& _pushTag1,
AssemblyItem const& _jumpi,
AssemblyItem const& _pushTag2,
AssemblyItem const& _jump,
AssemblyItem const& _tag1,
std::back_insert_iterator<AssemblyItems> _out
)
{
if (
_pushTag1.type() == PushTag &&
_jumpi == Instruction::JUMPI &&
_pushTag2.type() == PushTag &&
_jump == Instruction::JUMP &&
_tag1.type() == Tag &&
_pushTag1.data() == _tag1.data()
)
{
*_out = AssemblyItem(Instruction::ISZERO, _jumpi.location());
*_out = _pushTag2;
*_out = _jumpi;
*_out = _tag1;
return true;
}
else
return false;
}
};
struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext>
{
static size_t applySimple(
AssemblyItem const& _pushTag,
@@ -282,7 +347,7 @@ struct JumpToNext: SimplePeepholeOptimizerMethod<JumpToNext, 3>
}
};
struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions, 3>
struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions>
{
static bool applySimple(
AssemblyItem const& _pushTag,
@@ -317,7 +382,7 @@ struct TagConjunctions: SimplePeepholeOptimizerMethod<TagConjunctions, 3>
}
};
struct TruthyAnd: SimplePeepholeOptimizerMethod<TruthyAnd, 3>
struct TruthyAnd: SimplePeepholeOptimizerMethod<TruthyAnd>
{
static bool applySimple(
AssemblyItem const& _push,
@@ -394,8 +459,8 @@ bool PeepholeOptimiser::optimise()
while (state.i < m_items.size())
applyMethods(
state,
PushPop(), OpPop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
DupSwap(), IsZeroIsZeroJumpI(), JumpToNext(), UnreachableCode(),
PushPop(), OpPop(), OpStop(), DoublePush(), DoubleSwap(), CommutativeSwap(), SwapComparison(),
DupSwap(), IsZeroIsZeroJumpI(), EqIsZeroJumpI(), DoubleJump(), JumpToNext(), UnreachableCode(),
TagConjunctions(), TruthyAnd(), Identity()
);
if (m_optimisedItems.size() < m_items.size() || (
+3 -1
View File
@@ -121,7 +121,9 @@ vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(
Location::Memory,
Effect::Write,
paramCount - 2,
paramCount - 1,
// Length is in paramCount - 1, but it is only a max length,
// there is no guarantee that the full area is written to.
{},
{}
});
return operations;