diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 4791087b5..f281439bf 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -15,6 +15,8 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
add_executable(yul-phaser
yulPhaser/main.cpp
+ yulPhaser/Phaser.h
+ yulPhaser/Phaser.cpp
yulPhaser/GeneticAlgorithms.h
yulPhaser/GeneticAlgorithms.cpp
yulPhaser/Population.h
diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp
new file mode 100644
index 000000000..a1a955d57
--- /dev/null
+++ b/tools/yulPhaser/Phaser.cpp
@@ -0,0 +1,218 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include
+
+#include
+
+using namespace std;
+using namespace solidity;
+using namespace solidity::langutil;
+using namespace solidity::util;
+using namespace solidity::phaser;
+
+namespace po = boost::program_options;
+
+istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm)
+{
+ string value;
+ _inputStream >> value;
+
+ if (value == "random")
+ _algorithm = Algorithm::Random;
+ else if (value == "GEWEP")
+ _algorithm = Algorithm::GEWEP;
+ else
+ _inputStream.setstate(ios_base::failbit);
+
+ return _inputStream;
+}
+
+ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm)
+{
+ if (_algorithm == Algorithm::Random)
+ _outputStream << "random";
+ else if (_algorithm == Algorithm::GEWEP)
+ _outputStream << "GEWEP";
+ else
+ _outputStream.setstate(ios_base::failbit);
+
+ return _outputStream;
+}
+
+namespace
+{
+
+CharStream loadSource(string const& _sourcePath)
+{
+ assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist");
+
+ string sourceCode = readFileAsString(_sourcePath);
+ return CharStream(sourceCode, _sourcePath);
+}
+
+}
+
+int Phaser::main(int _argc, char** _argv)
+{
+ CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv);
+ if (parsingResult.exitCode != 0)
+ return parsingResult.exitCode;
+
+ initialiseRNG(parsingResult.arguments);
+
+ runAlgorithm(
+ parsingResult.arguments["input-file"].as(),
+ parsingResult.arguments["algorithm"].as()
+ );
+ return 0;
+}
+
+Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _argv)
+{
+ po::options_description description(
+ "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n"
+ "\n"
+ "Usage: yul-phaser [options] \n"
+ "Reads as Yul code and tries to find the best order in which to run optimisation"
+ " phases using a genetic algorithm.\n"
+ "Example:\n"
+ "yul-phaser program.yul\n"
+ "\n"
+ "Allowed options",
+ po::options_description::m_default_line_length,
+ po::options_description::m_default_line_length - 23
+ );
+
+ description.add_options()
+ ("help", "Show help message and exit.")
+ ("input-file", po::value()->required(), "Input file")
+ ("seed", po::value(), "Seed for the random number generator")
+ (
+ "algorithm",
+ po::value()->default_value(Algorithm::GEWEP),
+ "Algorithm"
+ )
+ ;
+
+ po::positional_options_description positionalDescription;
+ po::variables_map arguments;
+ positionalDescription.add("input-file", 1);
+ po::notify(arguments);
+
+ try
+ {
+ po::command_line_parser parser(_argc, _argv);
+ parser.options(description).positional(positionalDescription);
+ po::store(parser.run(), arguments);
+ }
+ catch (po::error const & _exception)
+ {
+ cerr << _exception.what() << endl;
+ return {1, move(arguments)};
+ }
+
+ if (arguments.count("help") > 0)
+ {
+ cout << description << endl;
+ return {2, move(arguments)};
+ }
+
+ if (arguments.count("input-file") == 0)
+ {
+ cerr << "Missing argument: input-file." << endl;
+ return {1, move(arguments)};
+ }
+
+ return {0, arguments};
+}
+
+void Phaser::initialiseRNG(po::variables_map const& _arguments)
+{
+ uint32_t seed;
+ if (_arguments.count("seed") > 0)
+ seed = _arguments["seed"].as();
+ else
+ seed = SimulationRNG::generateSeed();
+
+ SimulationRNG::reset(seed);
+ cout << "Random seed: " << seed << endl;
+}
+
+void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm)
+{
+ constexpr size_t populationSize = 20;
+ constexpr size_t minChromosomeLength = 12;
+ constexpr size_t maxChromosomeLength = 30;
+
+ CharStream sourceCode = loadSource(_sourcePath);
+ shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5);
+ auto population = Population::makeRandom(
+ fitnessMetric,
+ populationSize,
+ minChromosomeLength,
+ maxChromosomeLength
+ );
+
+ switch (_algorithm)
+ {
+ case Algorithm::Random:
+ {
+ RandomAlgorithm(
+ population,
+ cout,
+ {
+ /* elitePoolSize = */ 1.0 / populationSize,
+ /* minChromosomeLength = */ minChromosomeLength,
+ /* maxChromosomeLength = */ maxChromosomeLength,
+ }
+ ).run();
+
+ break;
+ }
+ case Algorithm::GEWEP:
+ {
+ GenerationalElitistWithExclusivePools(
+ population,
+ cout,
+ {
+ /* mutationPoolSize = */ 0.25,
+ /* crossoverPoolSize = */ 0.25,
+ /* randomisationChance = */ 0.9,
+ /* deletionVsAdditionChance = */ 0.5,
+ /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength,
+ /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength,
+ }
+ ).run();
+
+ break;
+ }
+ }
+}
diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h
new file mode 100644
index 000000000..65a82eba4
--- /dev/null
+++ b/tools/yulPhaser/Phaser.h
@@ -0,0 +1,64 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+/**
+ * Contains the main class that controls yul-phaser based on command-line parameters.
+ */
+
+#pragma once
+
+#include
+
+#include
+#include
+#include
+
+namespace solidity::phaser
+{
+
+enum class Algorithm
+{
+ Random,
+ GEWEP,
+};
+
+std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm);
+std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm);
+
+/**
+ * Main class that controls yul-phaser based on command-line parameters. The class is responsible
+ * for command-line parsing, initialisation of global objects (like the random number generator),
+ * creating instances of main components and running the genetic algorithm.
+ */
+class Phaser
+{
+public:
+ static int main(int argc, char** argv);
+
+private:
+ struct CommandLineParsingResult
+ {
+ int exitCode;
+ boost::program_options::variables_map arguments;
+ };
+
+ static CommandLineParsingResult parseCommandLine(int _argc, char** _argv);
+ static void initialiseRNG(boost::program_options::variables_map const& _arguments);
+
+ static void runAlgorithm(std::string const& _sourcePath, Algorithm _algorithm);
+};
+
+}
diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp
index 557a1f74e..eecaf6d3c 100644
--- a/tools/yulPhaser/main.cpp
+++ b/tools/yulPhaser/main.cpp
@@ -16,224 +16,19 @@
*/
#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
+#include
#include
-#include
-
-using namespace std;
-using namespace solidity::langutil;
-using namespace solidity::phaser;
-using namespace solidity::util;
-
-namespace po = boost::program_options;
-
-enum class Algorithm
-{
- Random,
- GEWEP
-};
-
-istream& operator>>(istream& _inputStream, Algorithm& _algorithm)
-{
- string value;
- _inputStream >> value;
-
- if (value == "random")
- _algorithm = Algorithm::Random;
- else if (value == "GEWEP")
- _algorithm = Algorithm::GEWEP;
- else
- _inputStream.setstate(ios_base::failbit);
-
- return _inputStream;
-}
-
-ostream& operator<<(ostream& _outputStream, Algorithm _algorithm)
-{
- if (_algorithm == Algorithm::Random)
- _outputStream << "random";
- else if (_algorithm == Algorithm::GEWEP)
- _outputStream << "GEWEP";
- else
- _outputStream.setstate(ios_base::failbit);
-
- return _outputStream;
-}
-
-namespace
-{
-
-struct CommandLineParsingResult
-{
- int exitCode;
- po::variables_map arguments;
-};
-
-
-void initialiseRNG(po::variables_map const& _arguments)
-{
- uint32_t seed;
- if (_arguments.count("seed") > 0)
- seed = _arguments["seed"].as();
- else
- seed = SimulationRNG::generateSeed();
-
- SimulationRNG::reset(seed);
- cout << "Random seed: " << seed << endl;
-}
-
-CharStream loadSource(string const& _sourcePath)
-{
- assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist");
-
- string sourceCode = readFileAsString(_sourcePath);
- return CharStream(sourceCode, _sourcePath);
-}
-
-void runAlgorithm(string const& _sourcePath, Algorithm _algorithm)
-{
- constexpr size_t populationSize = 20;
- constexpr size_t minChromosomeLength = 12;
- constexpr size_t maxChromosomeLength = 30;
-
- CharStream sourceCode = loadSource(_sourcePath);
- shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5);
- auto population = Population::makeRandom(
- fitnessMetric,
- populationSize,
- minChromosomeLength,
- maxChromosomeLength
- );
-
- switch (_algorithm)
- {
- case Algorithm::Random:
- {
- RandomAlgorithm(
- population,
- cout,
- {
- /* elitePoolSize = */ 1.0 / populationSize,
- /* minChromosomeLength = */ minChromosomeLength,
- /* maxChromosomeLength = */ maxChromosomeLength,
- }
- ).run();
-
- break;
- }
- case Algorithm::GEWEP:
- {
- GenerationalElitistWithExclusivePools(
- population,
- cout,
- {
- /* mutationPoolSize = */ 0.25,
- /* crossoverPoolSize = */ 0.25,
- /* randomisationChance = */ 0.9,
- /* deletionVsAdditionChance = */ 0.5,
- /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength,
- /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength,
- }
- ).run();
-
- break;
- }
- }
-}
-
-CommandLineParsingResult parseCommandLine(int _argc, char** _argv)
-{
- po::options_description description(
- "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n"
- "\n"
- "Usage: yul-phaser [options] \n"
- "Reads as Yul code and tries to find the best order in which to run optimisation"
- " phases using a genetic algorithm.\n"
- "Example:\n"
- "yul-phaser program.yul\n"
- "\n"
- "Allowed options",
- po::options_description::m_default_line_length,
- po::options_description::m_default_line_length - 23
- );
-
- description.add_options()
- ("help", "Show help message and exit.")
- ("input-file", po::value()->required(), "Input file")
- ("seed", po::value(), "Seed for the random number generator")
- (
- "algorithm",
- po::value()->default_value(Algorithm::GEWEP),
- "Algorithm"
- )
- ;
-
- po::positional_options_description positionalDescription;
- po::variables_map arguments;
- positionalDescription.add("input-file", 1);
- po::notify(arguments);
-
- try
- {
- po::command_line_parser parser(_argc, _argv);
- parser.options(description).positional(positionalDescription);
- po::store(parser.run(), arguments);
- }
- catch (po::error const & _exception)
- {
- cerr << _exception.what() << endl;
- return {1, move(arguments)};
- }
-
- if (arguments.count("help") > 0)
- {
- cout << description << endl;
- return {2, move(arguments)};
- }
-
- if (arguments.count("input-file") == 0)
- {
- cerr << "Missing argument: input-file." << endl;
- return {1, move(arguments)};
- }
-
- return {0, arguments};
-}
-
-}
int main(int argc, char** argv)
{
- CommandLineParsingResult parsingResult = parseCommandLine(argc, argv);
- if (parsingResult.exitCode != 0)
- return parsingResult.exitCode;
-
- initialiseRNG(parsingResult.arguments);
-
try
{
- runAlgorithm(
- parsingResult.arguments["input-file"].as(),
- parsingResult.arguments["algorithm"].as()
- );
+ return solidity::phaser::Phaser::main(argc, argv);
}
- catch (InvalidProgram const& _exception)
+ catch (solidity::phaser::InvalidProgram const& exception)
{
- cerr << "ERROR: " << _exception.what() << endl;
+ std::cerr << "ERROR: " << exception.what() << std::endl;
return 1;
}
-
- return 0;
}