mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
OptimizerSuite: Rewrite runSequence() with support for nested brackets
This commit is contained in:
+74
-34
@@ -79,6 +79,7 @@
|
||||
#include <range/v3/action/remove.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@@ -308,10 +309,50 @@ void OptimiserSuite::validateSequence(string_view _stepAbbreviations)
|
||||
assertThrow(nestingLevel == 0, OptimizerException, "Unbalanced brackets");
|
||||
}
|
||||
|
||||
void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast)
|
||||
void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable)
|
||||
{
|
||||
validateSequence(_stepAbbreviations);
|
||||
|
||||
// This splits 'aaa[bbb]ccc...' into 'aaa' and '[bbb]ccc...'.
|
||||
auto extractNonNestedPrefix = [](string_view _tail) -> tuple<string_view, string_view>
|
||||
{
|
||||
for (size_t i = 0; i < _tail.size(); ++i)
|
||||
{
|
||||
yulAssert(_tail[i] != ']');
|
||||
if (_tail[i] == '[')
|
||||
return {_tail.substr(0, i), _tail.substr(i)};
|
||||
}
|
||||
return {_tail, {}};
|
||||
};
|
||||
|
||||
// This splits '[bbb]ccc...' into 'bbb' and 'ccc...'.
|
||||
auto extractBracketContent = [](string_view _tail) -> tuple<string_view, string_view>
|
||||
{
|
||||
yulAssert(!_tail.empty() && _tail[0] == '[');
|
||||
|
||||
size_t contentLength = 0;
|
||||
int8_t nestingLevel = 1;
|
||||
for (char abbreviation: _tail.substr(1))
|
||||
{
|
||||
if (abbreviation == '[')
|
||||
{
|
||||
yulAssert(nestingLevel < numeric_limits<int8_t>::max());
|
||||
++nestingLevel;
|
||||
}
|
||||
else if (abbreviation == ']')
|
||||
{
|
||||
--nestingLevel;
|
||||
if (nestingLevel == 0)
|
||||
break;
|
||||
}
|
||||
++contentLength;
|
||||
}
|
||||
yulAssert(nestingLevel == 0);
|
||||
yulAssert(_tail[contentLength + 1] == ']');
|
||||
|
||||
return {_tail.substr(1, contentLength), _tail.substr(contentLength + 2)};
|
||||
};
|
||||
|
||||
auto abbreviationsToSteps = [](string_view _sequence) -> vector<string>
|
||||
{
|
||||
vector<string> steps;
|
||||
@@ -321,21 +362,41 @@ void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast)
|
||||
return steps;
|
||||
};
|
||||
|
||||
// The sequence has now been validated and must consist of pairs of segments that look like this: `aaa[bbb]`
|
||||
// `aaa` or `[bbb]` can be empty. For example we consider a sequence like `fgo[aaf]Oo` to have
|
||||
// four segments, the last of which is an empty bracket.
|
||||
size_t currentPairStart = 0;
|
||||
while (currentPairStart < _stepAbbreviations.size())
|
||||
vector<tuple<string_view, bool>> subsequences;
|
||||
string_view tail = _stepAbbreviations;
|
||||
while (!tail.empty())
|
||||
{
|
||||
size_t openingBracket = _stepAbbreviations.find('[', currentPairStart);
|
||||
size_t closingBracket = _stepAbbreviations.find(']', openingBracket);
|
||||
size_t firstCharInside = (openingBracket == string::npos ? _stepAbbreviations.size() : openingBracket + 1);
|
||||
yulAssert((openingBracket == string::npos) == (closingBracket == string::npos), "");
|
||||
string_view subsequence;
|
||||
tie(subsequence, tail) = extractNonNestedPrefix(tail);
|
||||
if (subsequence.size() > 0)
|
||||
subsequences.push_back({subsequence, false});
|
||||
|
||||
runSequence(abbreviationsToSteps(_stepAbbreviations.substr(currentPairStart, openingBracket - currentPairStart)), _ast);
|
||||
runSequenceUntilStable(abbreviationsToSteps(_stepAbbreviations.substr(firstCharInside, closingBracket - firstCharInside)), _ast);
|
||||
if (tail.empty())
|
||||
break;
|
||||
|
||||
currentPairStart = (closingBracket == string::npos ? _stepAbbreviations.size() : closingBracket + 1);
|
||||
tie(subsequence, tail) = extractBracketContent(tail);
|
||||
if (subsequence.size() > 0)
|
||||
subsequences.push_back({subsequence, true});
|
||||
}
|
||||
|
||||
size_t codeSize = 0;
|
||||
for (size_t round = 0; round < MaxRounds; ++round)
|
||||
{
|
||||
for (auto const& [subsequence, repeat]: subsequences)
|
||||
{
|
||||
if (repeat)
|
||||
runSequence(subsequence, _ast, true);
|
||||
else
|
||||
runSequence(abbreviationsToSteps(subsequence), _ast);
|
||||
}
|
||||
|
||||
if (!_repeatUntilStable)
|
||||
break;
|
||||
|
||||
size_t newSize = CodeSize::codeSizeIncludingFunctions(_ast);
|
||||
if (newSize == codeSize)
|
||||
break;
|
||||
codeSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,24 +424,3 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OptimiserSuite::runSequenceUntilStable(
|
||||
std::vector<string> const& _steps,
|
||||
Block& _ast,
|
||||
size_t maxRounds
|
||||
)
|
||||
{
|
||||
if (_steps.empty())
|
||||
return;
|
||||
|
||||
size_t codeSize = 0;
|
||||
for (size_t rounds = 0; rounds < maxRounds; ++rounds)
|
||||
{
|
||||
size_t newSize = CodeSize::codeSizeIncludingFunctions(_ast);
|
||||
if (newSize == codeSize)
|
||||
break;
|
||||
codeSize = newSize;
|
||||
|
||||
runSequence(_steps, _ast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,12 +75,7 @@ public:
|
||||
static void validateSequence(std::string_view _stepAbbreviations);
|
||||
|
||||
void runSequence(std::vector<std::string> const& _steps, Block& _ast);
|
||||
void runSequence(std::string_view _stepAbbreviations, Block& _ast);
|
||||
void runSequenceUntilStable(
|
||||
std::vector<std::string> const& _steps,
|
||||
Block& _ast,
|
||||
size_t maxRounds = MaxRounds
|
||||
);
|
||||
void runSequence(std::string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable = false);
|
||||
|
||||
static std::map<std::string, std::unique_ptr<OptimiserStep>> const& allSteps();
|
||||
static std::map<std::string, char> const& stepNameToAbbreviationMap();
|
||||
|
||||
Reference in New Issue
Block a user