mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -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
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
@@ -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
@@ -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() || (
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user