mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #7420 from ethereum/develop
Merge develop into develop_060
This commit is contained in:
		
						commit
						50ce3b0ac8
					
				| @ -88,10 +88,11 @@ Solidity includes different types of tests, most of them bundled into the | ||||
| `Boost C++ Test Framework <https://www.boost.org/doc/libs/1_69_0/libs/test/doc/html/index.html>`_ application ``soltest``. | ||||
| Running ``build/test/soltest` or its wrapper ``scripts/soltest.sh`` is sufficient for most changes. | ||||
| 
 | ||||
| Some tests require the ``libevmone.so`` library, others require ``libz3``. | ||||
| Some tests require the ``evmone`` library, others require ``libz3``. | ||||
| 
 | ||||
| The test system will automatically try to discover the location of ``libevmone.so`` | ||||
| starting from the current directory. If it does not find it, the relevant tests | ||||
| The test system will automatically try to discover the location of the ``evmone`` library | ||||
| starting from the current directory. The required file is called ``libevmone.so`` on Linux systems, | ||||
| ``evmone.dll`` on Windows systems and ``libevmone.dylib`` on MacOS. If it is not found, the relevant tests | ||||
| are skipped. To run all tests, download the library from | ||||
| `Github <https://github.com/ethereum/evmone/releases/tag/v0.1.0>`_ | ||||
| and either place it in the project root path or inside the ``deps`` folder. | ||||
|  | ||||
| @ -61,6 +61,7 @@ struct Dialect: boost::noncopyable | ||||
| 
 | ||||
| 	virtual BuiltinFunction const* discardFunction() const { return nullptr; } | ||||
| 	virtual BuiltinFunction const* equalityFunction() const { return nullptr; } | ||||
| 	virtual BuiltinFunction const* booleanNegationFunction() const { return nullptr; } | ||||
| 
 | ||||
| 	virtual std::set<YulString> fixedFunctionNames() const { return {}; } | ||||
| 
 | ||||
|  | ||||
| @ -70,6 +70,7 @@ struct EVMDialect: public Dialect | ||||
| 
 | ||||
| 	BuiltinFunctionForEVM const* discardFunction() const override { return builtin("pop"_yulstring); } | ||||
| 	BuiltinFunctionForEVM const* equalityFunction() const override { return builtin("eq"_yulstring); } | ||||
| 	BuiltinFunctionForEVM const* booleanNegationFunction() const override { return builtin("iszero"_yulstring); } | ||||
| 
 | ||||
| 	static EVMDialect const& looseAssemblyForEVM(langutil::EVMVersion _version); | ||||
| 	static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version); | ||||
|  | ||||
| @ -47,6 +47,7 @@ struct WasmDialect: public Dialect | ||||
| 	BuiltinFunction const* builtin(YulString _name) const override; | ||||
| 	BuiltinFunction const* discardFunction() const override { return builtin("drop"_yulstring); } | ||||
| 	BuiltinFunction const* equalityFunction() const override { return builtin("i64.eq"_yulstring); } | ||||
| 	BuiltinFunction const* booleanNegationFunction() const override { return builtin("i64.eqz"_yulstring); } | ||||
| 
 | ||||
| 	std::set<YulString> fixedFunctionNames() const override { return {"main"_yulstring}; } | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,7 @@ using namespace yul; | ||||
| 
 | ||||
| void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) | ||||
| { | ||||
| 	if (_forLoop.condition->type() != typeid(Literal)) | ||||
| 	if (m_dialect.booleanNegationFunction() && _forLoop.condition->type() != typeid(Literal)) | ||||
| 	{ | ||||
| 		langutil::SourceLocation loc = locationOf(*_forLoop.condition); | ||||
| 		_forLoop.body.statements.insert( | ||||
| @ -33,9 +33,9 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop) | ||||
| 			If { | ||||
| 				loc, | ||||
| 				make_unique<Expression>( | ||||
| 					FunctionalInstruction { | ||||
| 					FunctionCall { | ||||
| 						loc, | ||||
| 						eth::Instruction::ISZERO, | ||||
| 						{loc, m_dialect.booleanNegationFunction()->name}, | ||||
| 						make_vector<Expression>(std::move(*_forLoop.condition)) | ||||
| 					} | ||||
| 				), | ||||
|  | ||||
| @ -17,6 +17,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <libyul/optimiser/ASTWalker.h> | ||||
| #include <libyul/Dialect.h> | ||||
| 
 | ||||
| namespace yul | ||||
| { | ||||
| @ -29,17 +30,22 @@ namespace yul | ||||
|  * By moving the iteration check part into the ForLoop body, we can apply expression splitter | ||||
|  * to the condition expression. | ||||
|  * | ||||
|  * This rewritter will skip loops that already have literal constant as iteration condition. | ||||
|  * This rewriter will skip loops that already have literal constant as iteration condition. | ||||
|  * | ||||
|  * Requirements: | ||||
|  * - The Disambiguator must be run upfront. | ||||
|  * - To avoid unnecessary rewrite, it is recommended to run this rewriter after StructuralSimplifier. | ||||
|  * - Only works for dialects with a builtin boolean negation function. | ||||
|  */ | ||||
| class ForLoopConditionIntoBody: public ASTModifier | ||||
| { | ||||
| public: | ||||
| 	ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {} | ||||
| 	using ASTModifier::operator(); | ||||
| 	void operator()(ForLoop& _forLoop) override; | ||||
| 
 | ||||
| private: | ||||
| 	Dialect const& m_dialect; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -71,9 +71,9 @@ void Rematerialiser::visit(Expression& _e) | ||||
| 	if (_e.type() == typeid(Identifier)) | ||||
| 	{ | ||||
| 		Identifier& identifier = boost::get<Identifier>(_e); | ||||
| 		if (m_value.count(identifier.name)) | ||||
| 		YulString name = identifier.name; | ||||
| 		if (m_value.count(name)) | ||||
| 		{ | ||||
| 			YulString name = identifier.name; | ||||
| 			assertThrow(m_value.at(name), OptimizerException, ""); | ||||
| 			auto const& value = *m_value.at(name); | ||||
| 			size_t refs = m_referenceCounts[name]; | ||||
| @ -93,3 +93,20 @@ void Rematerialiser::visit(Expression& _e) | ||||
| 	} | ||||
| 	DataFlowAnalyzer::visit(_e); | ||||
| } | ||||
| 
 | ||||
| void LiteralRematerialiser::visit(Expression& _e) | ||||
| { | ||||
| 	if (_e.type() == typeid(Identifier)) | ||||
| 	{ | ||||
| 		Identifier& identifier = boost::get<Identifier>(_e); | ||||
| 		YulString name = identifier.name; | ||||
| 		if (m_value.count(name)) | ||||
| 		{ | ||||
| 			Expression const* value = m_value.at(name); | ||||
| 			assertThrow(value, OptimizerException, ""); | ||||
| 			if (value->type() == typeid(Literal)) | ||||
| 				_e = *value; | ||||
| 		} | ||||
| 	} | ||||
| 	DataFlowAnalyzer::visit(_e); | ||||
| } | ||||
|  | ||||
| @ -68,4 +68,25 @@ protected: | ||||
| 	std::set<YulString> m_varsToAlwaysRematerialize; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * If a variable is referenced that is known to have a literal | ||||
|  * value at that point, replace it by a literal. | ||||
|  * | ||||
|  * This is mostly used so that other components do not have to rely | ||||
|  * on the data flow analyzer. | ||||
|  * | ||||
|  * Prerequisite: Disambiguator, ForLoopInitRewriter. | ||||
|  */ | ||||
| class LiteralRematerialiser: public DataFlowAnalyzer | ||||
| { | ||||
| public: | ||||
| 	LiteralRematerialiser(Dialect const& _dialect): | ||||
| 		DataFlowAnalyzer(_dialect) | ||||
| 	{} | ||||
| 
 | ||||
| 	using ASTModifier::visit; | ||||
| 	void visit(Expression& _e) override; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -56,18 +56,24 @@ void SSAReverser::operator()(Block& _block) | ||||
| 					identifier && | ||||
| 					identifier->name == varDecl->variables.front().name | ||||
| 				) | ||||
| 					return make_vector<Statement>( | ||||
| 						Assignment{ | ||||
| 							std::move(assignment->location), | ||||
| 							assignment->variableNames, | ||||
| 							std::move(varDecl->value) | ||||
| 						}, | ||||
| 						VariableDeclaration{ | ||||
| 							std::move(varDecl->location), | ||||
| 							std::move(varDecl->variables), | ||||
| 							std::make_unique<Expression>(std::move(assignment->variableNames.front())) | ||||
| 						} | ||||
| 					); | ||||
| 				{ | ||||
| 					// in the special case a == a_1, just remove the assignment
 | ||||
| 					if (assignment->variableNames.front().name == identifier->name) | ||||
| 						return make_vector<Statement>(std::move(_stmt1)); | ||||
| 					else | ||||
| 						return make_vector<Statement>( | ||||
| 							Assignment{ | ||||
| 								std::move(assignment->location), | ||||
| 								assignment->variableNames, | ||||
| 								std::move(varDecl->value) | ||||
| 							}, | ||||
| 							VariableDeclaration{ | ||||
| 								std::move(varDecl->location), | ||||
| 								std::move(varDecl->variables), | ||||
| 								std::make_unique<Expression>(std::move(assignment->variableNames.front())) | ||||
| 							} | ||||
| 						); | ||||
| 				} | ||||
| 			} | ||||
| 			// Replaces
 | ||||
| 			//   let a_1 := E
 | ||||
|  | ||||
| @ -40,6 +40,13 @@ class AssignmentCounter; | ||||
|  * 		a := E | ||||
|  * 		let a_1 := a | ||||
|  * | ||||
|  * 	In the special case | ||||
|  * 		let a := E | ||||
|  * 		a := a | ||||
|  * | ||||
|  * 	the redundant assignment "a := a" is removed. | ||||
|  * | ||||
|  * | ||||
|  * Secondly, the SSA transform will rewrite | ||||
|  * | ||||
|  * 		let a := E | ||||
|  | ||||
| @ -61,29 +61,7 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const | ||||
| 
 | ||||
| void StructuralSimplifier::operator()(Block& _block) | ||||
| { | ||||
| 	pushScope(false); | ||||
| 	simplify(_block.statements); | ||||
| 	popScope(); | ||||
| } | ||||
| 
 | ||||
| boost::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const | ||||
| { | ||||
| 	Expression const* expr = &_expression; | ||||
| 
 | ||||
| 	if (expr->type() == typeid(Identifier)) | ||||
| 	{ | ||||
| 		Identifier const& ident = boost::get<Identifier>(*expr); | ||||
| 		if (m_value.count(ident.name)) | ||||
| 			expr = m_value.at(ident.name); | ||||
| 	} | ||||
| 
 | ||||
| 	if (expr && expr->type() == typeid(Literal)) | ||||
| 	{ | ||||
| 		Literal const& literal = boost::get<Literal>(*expr); | ||||
| 		return valueOfLiteral(literal); | ||||
| 	} | ||||
| 
 | ||||
| 	return boost::optional<u256>(); | ||||
| } | ||||
| 
 | ||||
| void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements) | ||||
| @ -124,34 +102,24 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements) | ||||
| 
 | ||||
| bool StructuralSimplifier::expressionAlwaysTrue(Expression const& _expression) | ||||
| { | ||||
| 	return boost::apply_visitor(GenericFallbackReturnsVisitor<bool, Identifier const, Literal const>( | ||||
| 		[&](Identifier const& _identifier) -> bool { | ||||
| 			if (auto expr = m_value[_identifier.name]) | ||||
| 				return expressionAlwaysTrue(*expr); | ||||
| 			return false; | ||||
| 		}, | ||||
| 		[](Literal const& _literal) -> bool { | ||||
| 			return | ||||
| 				(_literal.kind == LiteralKind::Boolean && _literal.value == "true"_yulstring) || | ||||
| 				(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) != u256(0)) | ||||
| 			; | ||||
| 		} | ||||
| 	), _expression); | ||||
| 	if (boost::optional<u256> value = hasLiteralValue(_expression)) | ||||
| 		return *value != 0; | ||||
| 	else | ||||
| 		return false; | ||||
| } | ||||
| 
 | ||||
| bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression) | ||||
| { | ||||
| 	return boost::apply_visitor(GenericFallbackReturnsVisitor<bool, Identifier const, Literal const>( | ||||
| 		[&](Identifier const& _identifier) -> bool { | ||||
| 			if (auto expr = m_value[_identifier.name]) | ||||
| 				return expressionAlwaysFalse(*expr); | ||||
| 			return false; | ||||
| 		}, | ||||
| 		[](Literal const& _literal) -> bool { | ||||
| 			return | ||||
| 				(_literal.kind == LiteralKind::Boolean && _literal.value == "false"_yulstring) || | ||||
| 				(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) == u256(0)) | ||||
| 			; | ||||
| 		} | ||||
| 	), _expression); | ||||
| 	if (boost::optional<u256> value = hasLiteralValue(_expression)) | ||||
| 		return *value == 0; | ||||
| 	else | ||||
| 		return false; | ||||
| } | ||||
| 
 | ||||
| boost::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const | ||||
| { | ||||
| 	if (_expression.type() == typeid(Literal)) | ||||
| 		return valueOfLiteral(boost::get<Literal>(_expression)); | ||||
| 	else | ||||
| 		return boost::optional<u256>(); | ||||
| } | ||||
|  | ||||
| @ -30,16 +30,16 @@ namespace yul | ||||
|  * - replace switch with const expr with matching case body | ||||
|  * - replace for with false condition by its initialization part | ||||
|  * | ||||
|  * Prerequisite: Disambiguator, ForLoopInitRewriter. | ||||
|  * The LiteralRematerialiser should be run before this. | ||||
|  * | ||||
|  * Prerequisite: Disambiguator. | ||||
|  * | ||||
|  * Important: Can only be used on EVM code. | ||||
|  */ | ||||
| class StructuralSimplifier: public DataFlowAnalyzer | ||||
| class StructuralSimplifier: public ASTModifier | ||||
| { | ||||
| public: | ||||
| 	explicit StructuralSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {} | ||||
| 
 | ||||
| 	using DataFlowAnalyzer::operator(); | ||||
| 	using ASTModifier::operator(); | ||||
| 	void operator()(Block& _block) override; | ||||
| private: | ||||
| 	void simplify(std::vector<Statement>& _statements); | ||||
|  | ||||
| @ -33,6 +33,7 @@ | ||||
| #include <libyul/optimiser/ExpressionJoiner.h> | ||||
| #include <libyul/optimiser/ExpressionInliner.h> | ||||
| #include <libyul/optimiser/FullInliner.h> | ||||
| #include <libyul/optimiser/ForLoopConditionIntoBody.h> | ||||
| #include <libyul/optimiser/ForLoopInitRewriter.h> | ||||
| #include <libyul/optimiser/Rematerialiser.h> | ||||
| #include <libyul/optimiser/UnusedPruner.h> | ||||
| @ -91,8 +92,10 @@ void OptimiserSuite::run( | ||||
| 	UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); | ||||
| 	BlockFlattener{}(ast); | ||||
| 	ControlFlowSimplifier{_dialect}(ast); | ||||
| 	StructuralSimplifier{_dialect}(ast); | ||||
| 	LiteralRematerialiser{_dialect}(ast); | ||||
| 	StructuralSimplifier{}(ast); | ||||
| 	ControlFlowSimplifier{_dialect}(ast); | ||||
| 	ForLoopConditionIntoBody{_dialect}(ast); | ||||
| 	BlockFlattener{}(ast); | ||||
| 
 | ||||
| 	// None of the above can make stack problems worse.
 | ||||
| @ -125,7 +128,8 @@ void OptimiserSuite::run( | ||||
| 		{ | ||||
| 			// still in SSA, perform structural simplification
 | ||||
| 			ControlFlowSimplifier{_dialect}(ast); | ||||
| 			StructuralSimplifier{_dialect}(ast); | ||||
| 			LiteralRematerialiser{_dialect}(ast); | ||||
| 			StructuralSimplifier{}(ast); | ||||
| 			ControlFlowSimplifier{_dialect}(ast); | ||||
| 			BlockFlattener{}(ast); | ||||
| 			DeadCodeEliminator{_dialect}(ast); | ||||
| @ -182,7 +186,8 @@ void OptimiserSuite::run( | ||||
| 			RedundantAssignEliminator::run(_dialect, ast); | ||||
| 			LoadResolver::run(_dialect, ast); | ||||
| 			ExpressionSimplifier::run(_dialect, ast); | ||||
| 			StructuralSimplifier{_dialect}(ast); | ||||
| 			LiteralRematerialiser{_dialect}(ast); | ||||
| 			StructuralSimplifier{}(ast); | ||||
| 			BlockFlattener{}(ast); | ||||
| 			DeadCodeEliminator{_dialect}(ast); | ||||
| 			ControlFlowSimplifier{_dialect}(ast); | ||||
|  | ||||
| @ -76,7 +76,7 @@ std::string EVMOneEnvOrDefaultPath() | ||||
| 	}; | ||||
| 	for (auto const& basePath: searchPath) | ||||
| 	{ | ||||
| 		fs::path p = basePath / "libevmone.so"; | ||||
| 		fs::path p = basePath / evmoneFilename; | ||||
| 		if (fs::exists(p)) | ||||
| 			return p.string(); | ||||
| 	} | ||||
| @ -92,7 +92,7 @@ CommonOptions::CommonOptions(std::string _caption): | ||||
| 	options.add_options() | ||||
| 		("evm-version", po::value(&evmVersionString), "which evm version to use") | ||||
| 		("testpath", po::value<fs::path>(&this->testPath)->default_value(dev::test::testPath()), "path to test files") | ||||
| 		("evmonepath", po::value<fs::path>(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to libevmone.so") | ||||
| 		("evmonepath", po::value<fs::path>(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library") | ||||
| 		("no-smt", po::bool_switch(&disableSMT), "disable SMT checker"); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -30,6 +30,18 @@ namespace dev | ||||
| namespace test | ||||
| { | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| static constexpr auto evmoneFilename = "evmone.dll"; | ||||
| static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-windows-amd64.zip"; | ||||
| #elif defined(__APPLE__) | ||||
| static constexpr auto evmoneFilename = "libevmone.dylib"; | ||||
| static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-darwin-x86_64.tar.gz"; | ||||
| #else | ||||
| static constexpr auto evmoneFilename = "libevmone.so"; | ||||
| static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz"; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| struct ConfigException : public Exception {}; | ||||
| 
 | ||||
| struct CommonOptions: boost::noncopyable | ||||
|  | ||||
| @ -61,7 +61,7 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm): | ||||
| { | ||||
| 	if (!m_vm) | ||||
| 	{ | ||||
| 		cerr << "Unable to find library libevmone.so" << endl; | ||||
| 		cerr << "Unable to find evmone library" << endl; | ||||
| 		assertThrow(false, Exception, ""); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -143,9 +143,9 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) | ||||
| 	bool disableSemantics = !dev::test::EVMHost::getVM(dev::test::Options::get().evmonePath.string()); | ||||
| 	if (disableSemantics) | ||||
| 	{ | ||||
| 		cout << "Unable to find libevmone.so. Please provide the path using -- --evmonepath <path>." << endl; | ||||
| 		cout << "Unable to find " << dev::test::evmoneFilename << ". Please provide the path using -- --evmonepath <path>." << endl; | ||||
| 		cout << "You can download it at" << endl; | ||||
| 		cout << "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz" << endl; | ||||
| 		cout << dev::test::evmoneDownloadLink << endl; | ||||
| 		cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; | ||||
| 	} | ||||
| 	// Include the interactive tests in the automatic tests as well
 | ||||
|  | ||||
| @ -11,20 +11,20 @@ object "object" { | ||||
|         } | ||||
|         function fun() -> a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, n3, o3, p3 | ||||
|         { | ||||
|             let a := 1 | ||||
|             sstore(a, a) | ||||
|             sstore(2, a) | ||||
|             sstore(3, a) | ||||
|             sstore(4, a) | ||||
|             sstore(5, a) | ||||
|             sstore(6, a) | ||||
|             sstore(7, a) | ||||
|             sstore(8, a) | ||||
|             sstore(9, a) | ||||
|             sstore(10, a) | ||||
|             sstore(11, a) | ||||
|             sstore(12, a) | ||||
|             sstore(13, a) | ||||
|             let _1 := 1 | ||||
|             sstore(_1, _1) | ||||
|             sstore(2, _1) | ||||
|             sstore(3, _1) | ||||
|             sstore(4, _1) | ||||
|             sstore(5, _1) | ||||
|             sstore(6, _1) | ||||
|             sstore(7, _1) | ||||
|             sstore(8, _1) | ||||
|             sstore(9, _1) | ||||
|             sstore(10, _1) | ||||
|             sstore(11, _1) | ||||
|             sstore(12, _1) | ||||
|             sstore(13, _1) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -103,79 +103,77 @@ tag_2: | ||||
|   0x00 | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   0x01 | ||||
|     /* "yul_stack_opt/input.sol":139:140   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":136:137   */ | ||||
|   dup2 | ||||
|     /* "yul_stack_opt/input.sol":129:141   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":162:163   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":151:160   */ | ||||
|   0x02 | ||||
|     /* "yul_stack_opt/input.sol":144:164   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":185:186   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":174:183   */ | ||||
|   0x03 | ||||
|     /* "yul_stack_opt/input.sol":167:187   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":208:209   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":197:206   */ | ||||
|   0x04 | ||||
|     /* "yul_stack_opt/input.sol":190:210   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":231:232   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":220:229   */ | ||||
|   0x05 | ||||
|     /* "yul_stack_opt/input.sol":213:233   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":254:255   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":243:252   */ | ||||
|   0x06 | ||||
|     /* "yul_stack_opt/input.sol":236:256   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":277:278   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":266:275   */ | ||||
|   0x07 | ||||
|     /* "yul_stack_opt/input.sol":259:279   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":300:301   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":289:298   */ | ||||
|   0x08 | ||||
|     /* "yul_stack_opt/input.sol":282:302   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":323:324   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":312:321   */ | ||||
|   0x09 | ||||
|     /* "yul_stack_opt/input.sol":305:325   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":346:347   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":335:344   */ | ||||
|   0x0a | ||||
|     /* "yul_stack_opt/input.sol":328:348   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":370:371   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":358:368   */ | ||||
|   0x0b | ||||
|     /* "yul_stack_opt/input.sol":351:372   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":394:395   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":382:392   */ | ||||
|   0x0c | ||||
|     /* "yul_stack_opt/input.sol":375:396   */ | ||||
|   sstore | ||||
|     /* "yul_stack_opt/input.sol":418:419   */ | ||||
|     /* "yul_stack_opt/input.sol":98:99   */ | ||||
|   dup1 | ||||
|     /* "yul_stack_opt/input.sol":406:416   */ | ||||
|   0x0d | ||||
|  | ||||
| @ -17,9 +17,9 @@ contract C { | ||||
| // optimize-yul: true | ||||
| // ---- | ||||
| // creation: | ||||
| //   codeDepositCost: 610600 | ||||
| //   executionCost: 645 | ||||
| //   totalCost: 611245 | ||||
| //   codeDepositCost: 624200 | ||||
| //   executionCost: 657 | ||||
| //   totalCost: 624857 | ||||
| // external: | ||||
| //   a(): 429 | ||||
| //   b(uint256): 884 | ||||
|  | ||||
| @ -208,21 +208,21 @@ string BytesUtils::formatRawBytes( | ||||
| 	dev::solidity::test::ParameterList const& _parameters, | ||||
| 	string _linePrefix) | ||||
| { | ||||
| 	soltestAssert( | ||||
| 		_bytes.size() == ContractABIUtils::encodingSize(_parameters), | ||||
| 		"Got " + to_string(_bytes.size()) + " bytes, but expected " + | ||||
| 		to_string(ContractABIUtils::encodingSize(_parameters)) + " bytes." | ||||
| 	); | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 	ParameterList parameters; | ||||
| 	auto it = _bytes.begin(); | ||||
| 
 | ||||
| 	for (auto const& parameter: _parameters) | ||||
| 	if (_bytes.size() != ContractABIUtils::encodingSize(_parameters)) | ||||
| 		parameters = ContractABIUtils::defaultParameters(ceil(_bytes.size() / 32)); | ||||
| 	else | ||||
| 		parameters = _parameters; | ||||
| 
 | ||||
| 	for (auto const& parameter: parameters) | ||||
| 	{ | ||||
| 		bytes byteRange{it, it + static_cast<long>(parameter.abiType.size)}; | ||||
| 
 | ||||
| 		os << _linePrefix << byteRange; | ||||
| 		if (¶meter != &_parameters.back()) | ||||
| 		if (¶meter != ¶meters.back()) | ||||
| 			os << endl; | ||||
| 
 | ||||
| 		it += static_cast<long>(parameter.abiType.size); | ||||
| @ -279,16 +279,17 @@ string BytesUtils::formatBytesRange( | ||||
| 	bool _highlight | ||||
| ) | ||||
| { | ||||
| 	soltestAssert( | ||||
| 		_bytes.size() == ContractABIUtils::encodingSize(_parameters), | ||||
| 		"Got " + to_string(_bytes.size()) + " bytes, but expected " + | ||||
| 		to_string(ContractABIUtils::encodingSize(_parameters)) + " bytes." | ||||
| 	); | ||||
| 
 | ||||
| 	stringstream os; | ||||
| 	ParameterList parameters; | ||||
| 	auto it = _bytes.begin(); | ||||
| 
 | ||||
| 	for (auto const& parameter: _parameters) | ||||
| 	if (_bytes.size() != ContractABIUtils::encodingSize(_parameters)) | ||||
| 		parameters = ContractABIUtils::defaultParameters(ceil(_bytes.size() / 32)); | ||||
| 	else | ||||
| 		parameters = _parameters; | ||||
| 
 | ||||
| 
 | ||||
| 	for (auto const& parameter: parameters) | ||||
| 	{ | ||||
| 		bytes byteRange{it, it + static_cast<long>(parameter.abiType.size)}; | ||||
| 
 | ||||
| @ -301,7 +302,7 @@ string BytesUtils::formatBytesRange( | ||||
| 		else | ||||
| 			os << parameter.rawString; | ||||
| 
 | ||||
| 		if (¶meter != &_parameters.back()) | ||||
| 		if (¶meter != ¶meters.back()) | ||||
| 			os << ", "; | ||||
| 
 | ||||
| 		it += static_cast<long>(parameter.abiType.size); | ||||
|  | ||||
| @ -140,7 +140,11 @@ string TestFunctionCall::format( | ||||
| 
 | ||||
| 				string bytesOutput = abiParams ? | ||||
| 					BytesUtils::formatRawBytes(output, abiParams.get(), _linePrefix) : | ||||
| 					_linePrefix + "[]"; | ||||
| 					BytesUtils::formatRawBytes( | ||||
| 						output, | ||||
| 						ContractABIUtils::defaultParameters(ceil(output.size() / 32)), | ||||
| 						_linePrefix | ||||
| 					); | ||||
| 
 | ||||
| 				_errorReporter.warning( | ||||
| 					"The call to \"" + m_call.signature + "\" returned \n" + | ||||
|  | ||||
| @ -141,7 +141,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | ||||
| 	else if (m_optimizerStep == "forLoopConditionIntoBody") | ||||
| 	{ | ||||
| 		disambiguate(); | ||||
| 		ForLoopConditionIntoBody{}(*m_ast); | ||||
| 		ForLoopConditionIntoBody{*m_dialect}(*m_ast); | ||||
| 	} | ||||
| 	else if (m_optimizerStep == "forLoopInitRewriter") | ||||
| 	{ | ||||
| @ -279,7 +279,9 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | ||||
| 	else if (m_optimizerStep == "structuralSimplifier") | ||||
| 	{ | ||||
| 		disambiguate(); | ||||
| 		StructuralSimplifier{*m_dialect}(*m_ast); | ||||
| 		ForLoopInitRewriter{}(*m_ast); | ||||
| 		LiteralRematerialiser{*m_dialect}(*m_ast); | ||||
| 		StructuralSimplifier{}(*m_ast); | ||||
| 	} | ||||
| 	else if (m_optimizerStep == "equivalentFunctionCombiner") | ||||
| 	{ | ||||
|  | ||||
| @ -0,0 +1,77 @@ | ||||
| { | ||||
|     let _1 := 0 | ||||
|     let _33 := calldataload(_1) | ||||
|     let sum_50_141 := _1 | ||||
|     let sum_50_146 := _1 | ||||
|     let sum_50 := _1 | ||||
|     let length_51 := calldataload(_33) | ||||
|     let i_53_142 := _1 | ||||
|     let i_53_147 := _1 | ||||
|     let i_53 := _1 | ||||
|     for { } | ||||
|     1 | ||||
|     { | ||||
|         let _108 := 1 | ||||
|         let i_53_121 := add(i_53, _108) | ||||
|         let i_53_144 := i_53_121 | ||||
|         let i_53_149 := i_53_121 | ||||
|         i_53 := i_53_121 | ||||
|     } | ||||
|     { | ||||
|         let _109 := lt(i_53, length_51) | ||||
|         let _110 := iszero(_109) | ||||
|         if _110 { break } | ||||
|         let _114_128 := iszero(_109) | ||||
|         if _114_128 { revert(_1, _1) } | ||||
|         let _13_129 := 0x20 | ||||
|         let _115_130 := mul(i_53, _13_129) | ||||
|         let _116_131 := add(_33, _115_130) | ||||
|         let _117_132 := add(_116_131, _13_129) | ||||
|         let v_122_133 := calldataload(_117_132) | ||||
|         let sum_50_120 := add(sum_50, v_122_133) | ||||
|         let sum_50_143 := sum_50_120 | ||||
|         let sum_50_148 := sum_50_120 | ||||
|         sum_50 := sum_50_120 | ||||
|     } | ||||
|     sstore(_1, sum_50) | ||||
| } | ||||
| // ==== | ||||
| // step: commonSubexpressionEliminator | ||||
| // ---- | ||||
| // { | ||||
| //     let _1 := 0 | ||||
| //     let _33 := calldataload(_1) | ||||
| //     let sum_50_141 := _1 | ||||
| //     let sum_50_146 := _1 | ||||
| //     let sum_50 := _1 | ||||
| //     let length_51 := calldataload(_33) | ||||
| //     let i_53_142 := _1 | ||||
| //     let i_53_147 := _1 | ||||
| //     let i_53 := _1 | ||||
| //     for { } | ||||
| //     1 | ||||
| //     { | ||||
| //         let _108 := 1 | ||||
| //         let i_53_121 := add(i_53, _108) | ||||
| //         let i_53_144 := i_53_121 | ||||
| //         let i_53_149 := i_53_121 | ||||
| //         i_53 := i_53_121 | ||||
| //     } | ||||
| //     { | ||||
| //         let _109 := lt(i_53, length_51) | ||||
| //         let _110 := iszero(_109) | ||||
| //         if _110 { break } | ||||
| //         let _114_128 := _110 | ||||
| //         if _110 { revert(_1, _1) } | ||||
| //         let _13_129 := 0x20 | ||||
| //         let _115_130 := mul(i_53, _13_129) | ||||
| //         let _116_131 := add(_33, _115_130) | ||||
| //         let _117_132 := add(_116_131, _13_129) | ||||
| //         let v_122_133 := calldataload(_117_132) | ||||
| //         let sum_50_120 := add(sum_50, v_122_133) | ||||
| //         let sum_50_143 := sum_50_120 | ||||
| //         let sum_50_148 := sum_50_120 | ||||
| //         sum_50 := sum_50_120 | ||||
| //     } | ||||
| //     sstore(_1, sum_50) | ||||
| // } | ||||
| @ -462,34 +462,35 @@ | ||||
| // ---- | ||||
| // { | ||||
| //     { | ||||
| //         let _1 := 0x20 | ||||
| //         let _2 := 0 | ||||
| //         let _3 := mload(_2) | ||||
| //         let pos := _1 | ||||
| //         let length := mload(_3) | ||||
| //         mstore(_1, length) | ||||
| //         let _1 := 0 | ||||
| //         let _2 := mload(_1) | ||||
| //         let pos := 0x20 | ||||
| //         let pos_1 := pos | ||||
| //         let length := mload(_2) | ||||
| //         mstore(pos, length) | ||||
| //         pos := 64 | ||||
| //         let srcPtr := add(_3, _1) | ||||
| //         let i := _2 | ||||
| //         for { } lt(i, length) { i := add(i, 1) } | ||||
| //         let srcPtr := add(_2, pos_1) | ||||
| //         let i := _1 | ||||
| //         for { } 1 { i := add(i, 1) } | ||||
| //         { | ||||
| //             if iszero(lt(i, length)) { break } | ||||
| //             abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(srcPtr), pos) | ||||
| //             srcPtr := add(srcPtr, _1) | ||||
| //             srcPtr := add(srcPtr, pos_1) | ||||
| //             pos := add(pos, 0x60) | ||||
| //         } | ||||
| //         let _4 := mload(64) | ||||
| //         let _5 := mload(_1) | ||||
| //         if slt(sub(_4, _5), 128) { revert(_2, _2) } | ||||
| //         let offset := calldataload(add(_5, 64)) | ||||
| //         let _6 := 0xffffffffffffffff | ||||
| //         if gt(offset, _6) { revert(_2, _2) } | ||||
| //         let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_5, offset), _4) | ||||
| //         let offset_1 := calldataload(add(_5, 96)) | ||||
| //         if gt(offset_1, _6) { revert(_2, _2) } | ||||
| //         let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_5, offset_1), _4) | ||||
| //         sstore(calldataload(_5), calldataload(add(_5, _1))) | ||||
| //         let _3 := mload(64) | ||||
| //         let _4 := mload(pos_1) | ||||
| //         if slt(sub(_3, _4), 128) { revert(_1, _1) } | ||||
| //         let offset := calldataload(add(_4, 64)) | ||||
| //         let _5 := 0xffffffffffffffff | ||||
| //         if gt(offset, _5) { revert(_1, _1) } | ||||
| //         let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_4, offset), _3) | ||||
| //         let offset_1 := calldataload(add(_4, 96)) | ||||
| //         if gt(offset_1, _5) { revert(_1, _1) } | ||||
| //         let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_4, offset_1), _3) | ||||
| //         sstore(calldataload(_4), calldataload(add(_4, pos_1))) | ||||
| //         sstore(value2, value3) | ||||
| //         sstore(_2, pos) | ||||
| //         sstore(_1, pos) | ||||
| //     } | ||||
| //     function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset, end) -> array | ||||
| //     { | ||||
| @ -503,8 +504,9 @@ | ||||
| //         let src := add(offset, _1) | ||||
| //         if gt(add(add(offset, mul(length, 0x40)), _1), end) { revert(0, 0) } | ||||
| //         let i := 0 | ||||
| //         for { } lt(i, length) { i := add(i, 1) } | ||||
| //         for { } 1 { i := add(i, 1) } | ||||
| //         { | ||||
| //             if iszero(lt(i, length)) { break } | ||||
| //             if iszero(slt(add(src, 0x1f), end)) { revert(0, 0) } | ||||
| //             let dst_1 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(0x2)) | ||||
| //             let dst_2 := dst_1 | ||||
| @ -512,8 +514,9 @@ | ||||
| //             let _2 := add(src, 0x40) | ||||
| //             if gt(_2, end) { revert(0, 0) } | ||||
| //             let i_1 := 0 | ||||
| //             for { } lt(i_1, 0x2) { i_1 := add(i_1, 1) } | ||||
| //             for { } 1 { i_1 := add(i_1, 1) } | ||||
| //             { | ||||
| //                 if iszero(lt(i_1, 0x2)) { break } | ||||
| //                 mstore(dst_1, calldataload(src_1)) | ||||
| //                 dst_1 := add(dst_1, _1) | ||||
| //                 src_1 := add(src_1, _1) | ||||
| @ -535,8 +538,9 @@ | ||||
| //         let src := add(offset, _1) | ||||
| //         if gt(add(add(offset, mul(length, _1)), _1), end) { revert(0, 0) } | ||||
| //         let i := 0 | ||||
| //         for { } lt(i, length) { i := add(i, 1) } | ||||
| //         for { } 1 { i := add(i, 1) } | ||||
| //         { | ||||
| //             if iszero(lt(i, length)) { break } | ||||
| //             mstore(dst, calldataload(src)) | ||||
| //             dst := add(dst, _1) | ||||
| //             src := add(src, _1) | ||||
| @ -546,8 +550,9 @@ | ||||
| //     { | ||||
| //         let srcPtr := value | ||||
| //         let i := 0 | ||||
| //         for { } lt(i, 0x3) { i := add(i, 1) } | ||||
| //         for { } 1 { i := add(i, 1) } | ||||
| //         { | ||||
| //             if iszero(lt(i, 0x3)) { break } | ||||
| //             mstore(pos, and(mload(srcPtr), sub(shl(160, 1), 1))) | ||||
| //             srcPtr := add(srcPtr, 0x20) | ||||
| //             pos := add(pos, 0x20) | ||||
|  | ||||
| @ -238,8 +238,8 @@ | ||||
| //         let notes := add(0x04, calldataload(0x04)) | ||||
| //         let m := calldataload(0x24) | ||||
| //         let n := calldataload(notes) | ||||
| //         let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 | ||||
| //         let challenge := mod(calldataload(0x44), gen_order) | ||||
| //         let _1 := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 | ||||
| //         let challenge := mod(calldataload(0x44), _1) | ||||
| //         if gt(m, n) | ||||
| //         { | ||||
| //             mstore(0x00, 404) | ||||
| @ -249,72 +249,71 @@ | ||||
| //         mstore(0x2a0, caller()) | ||||
| //         mstore(0x2c0, kn) | ||||
| //         mstore(0x2e0, m) | ||||
| //         kn := mulmod(sub(gen_order, kn), challenge, gen_order) | ||||
| //         kn := mulmod(sub(_1, kn), challenge, _1) | ||||
| //         hashCommitments(notes, n) | ||||
| //         let b := add(0x300, mul(n, 0x80)) | ||||
| //         let i := 0 | ||||
| //         let i_1 := i | ||||
| //         for { } lt(i, n) { i := add(i, 0x01) } | ||||
| //         for { } 1 { i := add(i, 0x01) } | ||||
| //         { | ||||
| //             let _1 := add(calldataload(0x04), mul(i, 0xc0)) | ||||
| //             let noteIndex := add(_1, 0x24) | ||||
| //             if iszero(lt(i, n)) { break } | ||||
| //             let _2 := add(calldataload(0x04), mul(i, 0xc0)) | ||||
| //             let noteIndex := add(_2, 0x24) | ||||
| //             let k := i_1 | ||||
| //             let a := calldataload(add(_1, 0x44)) | ||||
| //             let a := calldataload(add(_2, 0x44)) | ||||
| //             let c := challenge | ||||
| //             let _2 := add(i, 0x01) | ||||
| //             switch eq(_2, n) | ||||
| //             let _3 := add(i, 0x01) | ||||
| //             switch eq(_3, n) | ||||
| //             case 1 { | ||||
| //                 k := kn | ||||
| //                 if eq(m, n) { k := sub(gen_order, kn) } | ||||
| //                 if eq(m, n) { k := sub(_1, kn) } | ||||
| //             } | ||||
| //             case 0 { k := calldataload(noteIndex) } | ||||
| //             validateCommitment(noteIndex, k, a) | ||||
| //             switch gt(_2, m) | ||||
| //             switch gt(_3, m) | ||||
| //             case 1 { | ||||
| //                 kn := addmod(kn, sub(gen_order, k), gen_order) | ||||
| //                 let x := mod(mload(i_1), gen_order) | ||||
| //                 k := mulmod(k, x, gen_order) | ||||
| //                 a := mulmod(a, x, gen_order) | ||||
| //                 c := mulmod(challenge, x, gen_order) | ||||
| //                 kn := addmod(kn, sub(_1, k), _1) | ||||
| //                 let x := mod(mload(i_1), _1) | ||||
| //                 k := mulmod(k, x, _1) | ||||
| //                 a := mulmod(a, x, _1) | ||||
| //                 c := mulmod(challenge, x, _1) | ||||
| //                 mstore(i_1, keccak256(i_1, 0x20)) | ||||
| //             } | ||||
| //             case 0 { | ||||
| //                 kn := addmod(kn, k, gen_order) | ||||
| //             } | ||||
| //             let _3 := 0x40 | ||||
| //             calldatacopy(0xe0, add(_1, 164), _3) | ||||
| //             calldatacopy(0x20, add(_1, 100), _3) | ||||
| //             mstore(0x120, sub(gen_order, c)) | ||||
| //             case 0 { kn := addmod(kn, k, _1) } | ||||
| //             let _4 := 0x40 | ||||
| //             calldatacopy(0xe0, add(_2, 164), _4) | ||||
| //             calldatacopy(0x20, add(_2, 100), _4) | ||||
| //             mstore(0x120, sub(_1, c)) | ||||
| //             mstore(0x60, k) | ||||
| //             mstore(0xc0, a) | ||||
| //             let result := call(gas(), 7, i_1, 0xe0, 0x60, 0x1a0, _3) | ||||
| //             let result_1 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x120, _3)) | ||||
| //             let result_2 := and(result_1, call(gas(), 7, i_1, 0x80, 0x60, 0x160, _3)) | ||||
| //             let result_3 := and(result_2, call(gas(), 6, i_1, 0x120, 0x80, 0x160, _3)) | ||||
| //             result := and(result_3, call(gas(), 6, i_1, 0x160, 0x80, b, _3)) | ||||
| //             let result := call(gas(), 7, i_1, 0xe0, 0x60, 0x1a0, _4) | ||||
| //             let result_1 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x120, _4)) | ||||
| //             let result_2 := and(result_1, call(gas(), 7, i_1, 0x80, 0x60, 0x160, _4)) | ||||
| //             let result_3 := and(result_2, call(gas(), 6, i_1, 0x120, 0x80, 0x160, _4)) | ||||
| //             result := and(result_3, call(gas(), 6, i_1, 0x160, 0x80, b, _4)) | ||||
| //             if eq(i, m) | ||||
| //             { | ||||
| //                 mstore(0x260, mload(0x20)) | ||||
| //                 mstore(0x280, mload(_3)) | ||||
| //                 mstore(0x280, mload(_4)) | ||||
| //                 mstore(0x1e0, mload(0xe0)) | ||||
| //                 mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) | ||||
| //             } | ||||
| //             if gt(i, m) | ||||
| //             { | ||||
| //                 mstore(0x60, c) | ||||
| //                 let result_4 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x220, _3)) | ||||
| //                 let result_5 := and(result_4, call(gas(), 6, i_1, 0x220, 0x80, 0x260, _3)) | ||||
| //                 result := and(result_5, call(gas(), 6, i_1, 0x1a0, 0x80, 0x1e0, _3)) | ||||
| //                 let result_4 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x220, _4)) | ||||
| //                 let result_5 := and(result_4, call(gas(), 6, i_1, 0x220, 0x80, 0x260, _4)) | ||||
| //                 result := and(result_5, call(gas(), 6, i_1, 0x1a0, 0x80, 0x1e0, _4)) | ||||
| //             } | ||||
| //             if iszero(result) | ||||
| //             { | ||||
| //                 mstore(i_1, 400) | ||||
| //                 revert(i_1, 0x20) | ||||
| //             } | ||||
| //             b := add(b, _3) | ||||
| //             b := add(b, _4) | ||||
| //         } | ||||
| //         if lt(m, n) { validatePairing(0x64) } | ||||
| //         if iszero(eq(mod(keccak256(0x2a0, add(b, not(671))), gen_order), challenge)) | ||||
| //         if iszero(eq(mod(keccak256(0x2a0, add(b, not(671))), _1), challenge)) | ||||
| //         { | ||||
| //             mstore(i_1, 404) | ||||
| //             revert(i_1, 0x20) | ||||
| @ -360,13 +359,13 @@ | ||||
| //     } | ||||
| //     function validateCommitment(note, k, a) | ||||
| //     { | ||||
| //         let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 | ||||
| //         let field_order := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 | ||||
| //         let gammaX := calldataload(add(note, 0x40)) | ||||
| //         let gammaY := calldataload(add(note, 0x60)) | ||||
| //         let sigmaX := calldataload(add(note, 0x80)) | ||||
| //         let sigmaY := calldataload(add(note, 0xa0)) | ||||
| //         if iszero(and(and(and(eq(mod(a, gen_order), a), gt(a, 1)), and(eq(mod(k, gen_order), k), gt(k, 1))), and(eq(addmod(mulmod(mulmod(sigmaX, sigmaX, field_order), sigmaX, field_order), 3, field_order), mulmod(sigmaY, sigmaY, field_order)), eq(addmod(mulmod(mulmod(gammaX, gammaX, field_order), gammaX, field_order), 3, field_order), mulmod(gammaY, gammaY, field_order))))) | ||||
| //         let _1 := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 | ||||
| //         let _2 := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 | ||||
| //         if iszero(and(and(and(eq(mod(a, _2), a), gt(a, 1)), and(eq(mod(k, _2), k), gt(k, 1))), and(eq(addmod(mulmod(mulmod(sigmaX, sigmaX, _1), sigmaX, _1), 3, _1), mulmod(sigmaY, sigmaY, _1)), eq(addmod(mulmod(mulmod(gammaX, gammaX, _1), gammaX, _1), 3, _1), mulmod(gammaY, gammaY, _1))))) | ||||
| //         { | ||||
| //             mstore(0x00, 400) | ||||
| //             revert(0x00, 0x20) | ||||
| @ -375,8 +374,9 @@ | ||||
| //     function hashCommitments(notes, n) | ||||
| //     { | ||||
| //         let i := 0 | ||||
| //         for { } lt(i, n) { i := add(i, 0x01) } | ||||
| //         for { } 1 { i := add(i, 0x01) } | ||||
| //         { | ||||
| //             if iszero(lt(i, n)) { break } | ||||
| //             calldatacopy(add(0x300, mul(i, 0x80)), add(add(notes, mul(i, 0xc0)), 0x60), 0x80) | ||||
| //         } | ||||
| //         mstore(0, keccak256(0x300, mul(n, 0x80))) | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| { | ||||
|     let a := calldataload(0) | ||||
|     a := a | ||||
| } | ||||
| // ==== | ||||
| // step: ssaReverser | ||||
| // ---- | ||||
| // { let a := calldataload(0) } | ||||
| @ -417,9 +417,9 @@ int main(int argc, char const *argv[]) | ||||
| 	bool disableSemantics = !dev::test::EVMHost::getVM(options.evmonePath.string()); | ||||
| 	if (disableSemantics) | ||||
| 	{ | ||||
| 		cout << "Unable to find libevmone.so. Please provide the path using --evmonepath <path>." << endl; | ||||
| 		cout << "Unable to find " << dev::test::evmoneFilename << ". Please provide the path using --evmonepath <path>." << endl; | ||||
| 		cout << "You can download it at" << endl; | ||||
| 		cout << "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz" << endl; | ||||
| 		cout << dev::test::evmoneDownloadLink << endl; | ||||
| 		cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; | ||||
| 	} | ||||
| 
 | ||||
| @ -462,7 +462,7 @@ int main(int argc, char const *argv[]) | ||||
| 	cout << "." << endl; | ||||
| 
 | ||||
| 	if (disableSemantics) | ||||
| 		cout << "\nNOTE: Skipped semantics tests because libevmone.so could not be found.\n" << endl; | ||||
| 		cout << "\nNOTE: Skipped semantics tests because " << dev::test::evmoneFilename << " could not be found.\n" << endl; | ||||
| 
 | ||||
| 	return global_stats ? 0 : 1; | ||||
| } | ||||
|  | ||||
| @ -17,24 +17,29 @@ if (OSSFUZZ) | ||||
| endif() | ||||
| 
 | ||||
| if (OSSFUZZ) | ||||
|     #[[FuzzingEngine.a is provided by oss-fuzz's Dockerized build environment]] | ||||
|     add_executable(solc_opt_ossfuzz solc_opt_ossfuzz.cpp ../fuzzer_common.cpp) | ||||
|     target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm FuzzingEngine.a) | ||||
|     target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm) | ||||
|     set_target_properties(solc_opt_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(solc_noopt_ossfuzz solc_noopt_ossfuzz.cpp ../fuzzer_common.cpp) | ||||
|     target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm FuzzingEngine.a) | ||||
|     target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm) | ||||
|     set_target_properties(solc_noopt_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(const_opt_ossfuzz const_opt_ossfuzz.cpp ../fuzzer_common.cpp) | ||||
|     target_link_libraries(const_opt_ossfuzz PRIVATE libsolc evmasm FuzzingEngine.a) | ||||
|     target_link_libraries(const_opt_ossfuzz PRIVATE libsolc evmasm) | ||||
|     set_target_properties(const_opt_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(strictasm_diff_ossfuzz strictasm_diff_ossfuzz.cpp yulFuzzerCommon.cpp) | ||||
|     target_link_libraries(strictasm_diff_ossfuzz PRIVATE libsolc evmasm yulInterpreter FuzzingEngine.a) | ||||
|     target_link_libraries(strictasm_diff_ossfuzz PRIVATE libsolc evmasm yulInterpreter) | ||||
|     set_target_properties(strictasm_diff_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(strictasm_opt_ossfuzz strictasm_opt_ossfuzz.cpp) | ||||
|     target_link_libraries(strictasm_opt_ossfuzz PRIVATE yul FuzzingEngine.a) | ||||
|     target_link_libraries(strictasm_opt_ossfuzz PRIVATE yul) | ||||
|     set_target_properties(strictasm_opt_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(strictasm_assembly_ossfuzz strictasm_assembly_ossfuzz.cpp) | ||||
|     target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul FuzzingEngine.a) | ||||
|     target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul) | ||||
|     set_target_properties(strictasm_assembly_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(yul_proto_ossfuzz yulProtoFuzzer.cpp protoToYul.cpp yulProto.pb.cc) | ||||
|     target_include_directories(yul_proto_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) | ||||
| @ -42,7 +47,8 @@ if (OSSFUZZ) | ||||
|             protobuf-mutator-libfuzzer.a | ||||
|             protobuf-mutator.a | ||||
|             protobuf.a | ||||
|             FuzzingEngine.a) | ||||
|     ) | ||||
|     set_target_properties(yul_proto_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(yul_proto_diff_ossfuzz yulProto_diff_ossfuzz.cpp yulFuzzerCommon.cpp protoToYul.cpp yulProto.pb.cc) | ||||
|     target_include_directories(yul_proto_diff_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) | ||||
| @ -51,7 +57,8 @@ if (OSSFUZZ) | ||||
|             protobuf-mutator-libfuzzer.a | ||||
|             protobuf-mutator.a | ||||
|             protobuf.a | ||||
|             FuzzingEngine.a) | ||||
|     ) | ||||
|     set_target_properties(yul_proto_diff_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| 
 | ||||
|     add_executable(abiv2_proto_ossfuzz | ||||
|             ../../EVMHost.cpp | ||||
| @ -68,8 +75,8 @@ if (OSSFUZZ) | ||||
|             protobuf-mutator-libfuzzer.a | ||||
|             protobuf-mutator.a | ||||
|             protobuf.a | ||||
|             FuzzingEngine.a | ||||
|     ) | ||||
|     set_target_properties(abiv2_proto_ossfuzz PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") | ||||
| else() | ||||
|     add_library(solc_opt_ossfuzz | ||||
|             solc_opt_ossfuzz.cpp | ||||
|  | ||||
| @ -54,6 +54,10 @@ string ProtoConverter::createHex(string const& _hexBytes) | ||||
| 	// Use a dictionary token.
 | ||||
| 	if (tmp.empty()) | ||||
| 		tmp = dictionaryToken(HexPrefix::DontAdd); | ||||
| 	// Hex literals must have even number of digits
 | ||||
| 	if (tmp.size() % 2) | ||||
| 		tmp.insert(0, "0"); | ||||
| 
 | ||||
| 	yulAssert(tmp.size() <= 64, "Proto Fuzzer: Dictionary token too large"); | ||||
| 	return tmp; | ||||
| } | ||||
| @ -158,6 +162,12 @@ void ProtoConverter::visit(Expression const& _x) | ||||
| 	case Expression::kCreate: | ||||
| 		visit(_x.create()); | ||||
| 		break; | ||||
| 	case Expression::kUnopdata: | ||||
| 		if (m_isObject) | ||||
| 			visit(_x.unopdata()); | ||||
| 		else | ||||
| 			m_output << dictionaryToken(); | ||||
| 		break; | ||||
| 	case Expression::EXPR_ONEOF_NOT_SET: | ||||
| 		m_output << dictionaryToken(); | ||||
| 		break; | ||||
| @ -432,7 +442,14 @@ void ProtoConverter::visit(NullaryOp const& _x) | ||||
| 
 | ||||
| void ProtoConverter::visit(CopyFunc const& _x) | ||||
| { | ||||
| 	switch (_x.ct()) | ||||
| 	CopyFunc_CopyType type = _x.ct(); | ||||
| 
 | ||||
| 	// datacopy() is valid only if we are inside
 | ||||
| 	// a yul object.
 | ||||
| 	if (type == CopyFunc::DATA && !m_isObject) | ||||
| 		return; | ||||
| 
 | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case CopyFunc::CALLDATA: | ||||
| 		m_output << "calldatacopy"; | ||||
| @ -443,6 +460,9 @@ void ProtoConverter::visit(CopyFunc const& _x) | ||||
| 	case CopyFunc::RETURNDATA: | ||||
| 		m_output << "returndatacopy"; | ||||
| 		break; | ||||
| 	case CopyFunc::DATA: | ||||
| 		m_output << "datacopy"; | ||||
| 		break; | ||||
| 	} | ||||
| 	m_output << "("; | ||||
| 	visit(_x.target()); | ||||
| @ -988,6 +1008,23 @@ void ProtoConverter::visit(TerminatingStmt const& _x) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(UnaryOpData const& _x) | ||||
| { | ||||
| 	switch (_x.op()) | ||||
| 	{ | ||||
| 	case UnaryOpData::SIZE: | ||||
| 		m_output << Whiskers(R"(datasize("<id>"))") | ||||
| 			("id", getObjectIdentifier(_x.identifier())) | ||||
| 			.render(); | ||||
| 		break; | ||||
| 	case UnaryOpData::OFFSET: | ||||
| 		m_output << Whiskers(R"(dataoffset("<id>"))") | ||||
| 			("id", getObjectIdentifier(_x.identifier())) | ||||
| 			.render(); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(Statement const& _x) | ||||
| { | ||||
| 	switch (_x.stmt_oneof_case()) | ||||
| @ -1347,21 +1384,89 @@ void ProtoConverter::visit(PopStmt const& _x) | ||||
| 	m_output << ")\n"; | ||||
| } | ||||
| 
 | ||||
| string ProtoConverter::getObjectIdentifier(ObjectId const& _x) | ||||
| { | ||||
| 	unsigned currentId = currentObjectId(); | ||||
| 	yulAssert(m_objectScopeTree.size() > currentId, "Proto fuzzer: Error referencing object"); | ||||
| 	std::vector<std::string> objectIdsInScope = m_objectScopeTree[currentId]; | ||||
| 	return objectIdsInScope[_x.id() % objectIdsInScope.size()]; | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(Code const& _x) | ||||
| { | ||||
| 	m_output << "code {\n"; | ||||
| 	visit(_x.block()); | ||||
| 	m_output << "}\n"; | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(Data const& _x) | ||||
| { | ||||
| 	// TODO: Generate random data block identifier
 | ||||
| 	m_output << "data \"" << s_dataIdentifier << "\" hex\"" << createHex(_x.hex()) << "\"\n"; | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(Object const& _x) | ||||
| { | ||||
| 	// object "object<n>" {
 | ||||
| 	// ...
 | ||||
| 	// }
 | ||||
| 	m_output << "object " << newObjectId() << " {\n"; | ||||
| 	visit(_x.code()); | ||||
| 	if (_x.has_data()) | ||||
| 		visit(_x.data()); | ||||
| 	if (_x.has_sub_obj()) | ||||
| 		visit(_x.sub_obj()); | ||||
| 	m_output << "}\n"; | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::buildObjectScopeTree(Object const& _x) | ||||
| { | ||||
| 	// Identifies object being visited
 | ||||
| 	string objectId = newObjectId(false); | ||||
| 	vector<string> node{objectId}; | ||||
| 	if (_x.has_data()) | ||||
| 		node.push_back(s_dataIdentifier); | ||||
| 	if (_x.has_sub_obj()) | ||||
| 	{ | ||||
| 		// Identifies sub object whose numeric suffix is
 | ||||
| 		// m_objectId
 | ||||
| 		string subObjectId = "object" + to_string(m_objectId); | ||||
| 		node.push_back(subObjectId); | ||||
| 		// TODO: Add sub-object to object's ancestors once
 | ||||
| 		// nested access is implemented.
 | ||||
| 		m_objectScopeTree.push_back(node); | ||||
| 		buildObjectScopeTree(_x.sub_obj()); | ||||
| 	} | ||||
| 	else | ||||
| 		m_objectScopeTree.push_back(node); | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(Program const& _x) | ||||
| { | ||||
| 	// Initialize input size
 | ||||
| 	m_inputSize = _x.ByteSizeLong(); | ||||
| 
 | ||||
| 	/* Program template is as follows
 | ||||
| 	 *      Zero or more statements. If function definition is present, it is | ||||
| 	 *      called post definition. | ||||
| 	 *          Example: function foo(x_0) -> x_1 {} | ||||
| 	 *                   x_2 := foo(calldataload(0)) | ||||
| 	 *                   sstore(0, x_2) | ||||
| 	 */ | ||||
| 	m_output << "{\n"; | ||||
| 	visit(_x.block()); | ||||
| 	m_output << "}\n"; | ||||
| 	// Program is either a yul object or a block of
 | ||||
| 	// statements.
 | ||||
| 	switch (_x.program_oneof_case()) | ||||
| 	{ | ||||
| 	case Program::kBlock: | ||||
| 		m_output << "{\n"; | ||||
| 		visit(_x.block()); | ||||
| 		m_output << "}\n"; | ||||
| 		break; | ||||
| 	case Program::kObj: | ||||
| 		m_isObject = true; | ||||
| 		buildObjectScopeTree(_x.obj()); | ||||
| 		// Reset object id counter
 | ||||
| 		m_objectId = 0; | ||||
| 		visit(_x.obj()); | ||||
| 		break; | ||||
| 	case Program::PROGRAM_ONEOF_NOT_SET: | ||||
| 		// {} is a trivial yul program
 | ||||
| 		m_output << "{}"; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| string ProtoConverter::programToString(Program const& _input) | ||||
|  | ||||
| @ -26,8 +26,10 @@ | ||||
| #include <tuple> | ||||
| 
 | ||||
| #include <test/tools/ossfuzz/yulProto.pb.h> | ||||
| 
 | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/FixedHash.h> | ||||
| #include <libdevcore/Whiskers.h> | ||||
| 
 | ||||
| namespace yul | ||||
| { | ||||
| @ -46,6 +48,8 @@ public: | ||||
| 		m_counter = 0; | ||||
| 		m_inputSize = 0; | ||||
| 		m_inFunctionDef = false; | ||||
| 		m_objectId = 0; | ||||
| 		m_isObject = false; | ||||
| 	} | ||||
| 	ProtoConverter(ProtoConverter const&) = delete; | ||||
| 	ProtoConverter(ProtoConverter&&) = delete; | ||||
| @ -88,6 +92,10 @@ private: | ||||
| 	void visit(PopStmt const&); | ||||
| 	void visit(LowLevelCall const&); | ||||
| 	void visit(Create const&); | ||||
| 	void visit(UnaryOpData const&); | ||||
| 	void visit(Object const&); | ||||
| 	void visit(Data const&); | ||||
| 	void visit(Code const&); | ||||
| 	void visit(Program const&); | ||||
| 
 | ||||
| 	/// Creates a new scope, and adds @a _funcParams to it if it
 | ||||
| @ -109,6 +117,7 @@ private: | ||||
| 	/// Accepts an arbitrary string, removes all characters that are neither
 | ||||
| 	/// alphabets nor digits from it and returns the said string.
 | ||||
| 	std::string createAlphaNum(std::string const& _strBytes); | ||||
| 
 | ||||
| 	enum class NumFunctionReturns | ||||
| 	{ | ||||
| 		None, | ||||
| @ -233,6 +242,11 @@ private: | ||||
| 	/// Removes entry from m_functionMap and m_functionName
 | ||||
| 	void updateFunctionMaps(std::string const& _x); | ||||
| 
 | ||||
| 	/// Build a tree of objects that contains the object/data
 | ||||
| 	/// identifiers that are in scope in a given object.
 | ||||
| 	/// @param _x root object of the yul protobuf specification.
 | ||||
| 	void buildObjectScopeTree(Object const& _x); | ||||
| 
 | ||||
| 	/// Returns a pseudo-random dictionary token.
 | ||||
| 	/// @param _p Enum that decides if the returned token is hex prefixed ("0x") or not
 | ||||
| 	/// @return Dictionary token at the index computed using a
 | ||||
| @ -256,6 +270,30 @@ private: | ||||
| 		return "foo_" + functionTypeToString(_type) + "_" + std::to_string(counter()); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns a pseudo-randomly chosen object identifier that is in the
 | ||||
| 	/// scope of the Yul object being visited.
 | ||||
| 	std::string getObjectIdentifier(ObjectId const& _x); | ||||
| 
 | ||||
| 	/// Return new object identifier as string. Identifier string
 | ||||
| 	/// is a template of the form "\"object<n>\"" where <n> is
 | ||||
| 	/// a monotonically increasing object ID counter.
 | ||||
| 	/// @param _decorate If true (default value), object ID is
 | ||||
| 	/// enclosed within double quotes.
 | ||||
| 	std::string newObjectId(bool _decorate = true) | ||||
| 	{ | ||||
| 		return dev::Whiskers(R"(<?decorate>"</decorate>object<id><?decorate>"</decorate>)") | ||||
| 			("decorate", _decorate) | ||||
| 			("id", std::to_string(m_objectId++)) | ||||
| 			.render(); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns the object counter value corresponding to the object
 | ||||
| 	/// being visited.
 | ||||
| 	unsigned currentObjectId() | ||||
| 	{ | ||||
| 		return m_objectId - 1; | ||||
| 	} | ||||
| 
 | ||||
| 	std::ostringstream m_output; | ||||
| 	/// Variables in current scope
 | ||||
| 	std::stack<std::vector<std::string>> m_scopeVars; | ||||
| @ -271,9 +309,13 @@ private: | ||||
| 	std::stack<std::set<dev::u256>> m_switchLiteralSetPerScope; | ||||
| 	// Look-up table per function type that holds the number of input (output) function parameters
 | ||||
| 	std::map<std::string, std::pair<unsigned, unsigned>> m_functionSigMap; | ||||
| 	/// Tree of objects and their scopes
 | ||||
| 	std::vector<std::vector<std::string>> m_objectScopeTree; | ||||
| 	// mod input/output parameters impose an upper bound on the number of input/output parameters a function may have.
 | ||||
| 	static unsigned constexpr s_modInputParams = 5; | ||||
| 	static unsigned constexpr s_modOutputParams = 5; | ||||
| 	/// Hard-coded identifier for a Yul object's data block
 | ||||
| 	static auto constexpr s_dataIdentifier = "datablock"; | ||||
| 	/// Predicate to keep track of for body scope. If true, break/continue
 | ||||
| 	/// statements can not be created.
 | ||||
| 	bool m_inForBodyScope; | ||||
| @ -288,6 +330,11 @@ private: | ||||
| 	unsigned m_inputSize; | ||||
| 	/// Predicate that is true if inside function definition, false otherwise
 | ||||
| 	bool m_inFunctionDef; | ||||
| 	/// Index used for naming objects
 | ||||
| 	unsigned m_objectId; | ||||
| 	/// Flag to track whether program is an object (true) or a statement block
 | ||||
| 	/// (false: default value)
 | ||||
| 	bool m_isObject; | ||||
| }; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -167,6 +167,15 @@ message UnaryOp { | ||||
|   required Expression operand = 2; | ||||
| } | ||||
| 
 | ||||
| message UnaryOpData { | ||||
|   enum UOpData { | ||||
|     SIZE = 1; | ||||
|     OFFSET = 2; | ||||
|   } | ||||
|   required UOpData op = 1; | ||||
|   required ObjectId identifier = 2; | ||||
| } | ||||
| 
 | ||||
| message TernaryOp { | ||||
|   enum TOp { | ||||
|     ADDM = 0; | ||||
| @ -183,6 +192,7 @@ message CopyFunc { | ||||
|     CALLDATA = 0; | ||||
|     CODE = 1; | ||||
|     RETURNDATA = 2; | ||||
|     DATA = 3; | ||||
|   } | ||||
|   required CopyType ct = 1; | ||||
|   required Expression target = 2; | ||||
| @ -197,6 +207,18 @@ message ExtCodeCopy { | ||||
|   required Expression size = 4; | ||||
| } | ||||
| 
 | ||||
| message ObjectId { | ||||
|   required uint64 id = 1; | ||||
| } | ||||
| 
 | ||||
| message DataSize { | ||||
|   required ObjectId identifier = 1; | ||||
| } | ||||
| 
 | ||||
| message DataOffset { | ||||
|   required ObjectId identifier = 1; | ||||
| } | ||||
| 
 | ||||
| message NullaryOp { | ||||
|   enum NOp { | ||||
|     PC = 1; | ||||
| @ -258,6 +280,7 @@ message Expression { | ||||
|     FunctionCall func_expr = 7; | ||||
|     LowLevelCall lowcall = 8; | ||||
|     Create create = 9; | ||||
|     UnaryOpData unopdata = 10; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @ -362,8 +385,25 @@ message Block { | ||||
|   repeated Statement statements = 1; | ||||
| } | ||||
| 
 | ||||
| message Program { | ||||
| message Object { | ||||
|   required Code code = 1; | ||||
|   optional Data data = 2; | ||||
|   optional Object sub_obj = 3; | ||||
| } | ||||
| 
 | ||||
| message Code { | ||||
|   required Block block = 1; | ||||
| } | ||||
| 
 | ||||
| message Data { | ||||
|   required string hex = 1; | ||||
| } | ||||
| 
 | ||||
| message Program { | ||||
|   oneof program_oneof { | ||||
|     Block block = 1; | ||||
|     Object obj = 2; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| package yul.test.yul_fuzzer; | ||||
|  | ||||
| @ -25,7 +25,9 @@ | ||||
| #include <libyul/AssemblyStack.h> | ||||
| #include <libyul/backends/evm/EVMDialect.h> | ||||
| #include <libyul/Exceptions.h> | ||||
| 
 | ||||
| #include <liblangutil/EVMVersion.h> | ||||
| #include <liblangutil/SourceReferenceFormatter.h> | ||||
| 
 | ||||
| #include <test/tools/ossfuzz/yulFuzzerCommon.h> | ||||
| 
 | ||||
| @ -37,6 +39,20 @@ using namespace langutil; | ||||
| using namespace dev; | ||||
| using namespace yul::test; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| void printErrors(ostream& _stream, ErrorList const& _errors) | ||||
| { | ||||
| 	SourceReferenceFormatter formatter(_stream); | ||||
| 
 | ||||
| 	for (auto const& error: _errors) | ||||
| 		formatter.printExceptionInformation( | ||||
| 			*error, | ||||
| 			(error->type() == Error::Type::Warning) ? "Warning" : "Error" | ||||
| 		); | ||||
| } | ||||
| } | ||||
| 
 | ||||
| DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| { | ||||
| 	ProtoConverter converter; | ||||
| @ -67,7 +83,10 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 		// Parse protobuf mutated YUL code
 | ||||
| 		if (!stack.parseAndAnalyze("source", yul_source) || !stack.parserResult()->code || | ||||
| 			!stack.parserResult()->analysisInfo) | ||||
| 		{ | ||||
| 			printErrors(std::cout, stack.errors()); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	catch (Exception const&) | ||||
| 	{ | ||||
|  | ||||
| @ -151,7 +151,7 @@ public: | ||||
| 				ForLoopInitRewriter{}(*m_ast); | ||||
| 				break; | ||||
| 			case 'O': | ||||
| 				ForLoopConditionIntoBody{}(*m_ast); | ||||
| 				ForLoopConditionIntoBody{m_dialect}(*m_ast); | ||||
| 				break; | ||||
| 			case 'c': | ||||
| 				CommonSubexpressionEliminator::run(m_dialect, *m_ast); | ||||
| @ -184,7 +184,7 @@ public: | ||||
| 				ExpressionSimplifier::run(m_dialect, *m_ast); | ||||
| 				break; | ||||
| 			case 't': | ||||
| 				(StructuralSimplifier{m_dialect})(*m_ast); | ||||
| 				StructuralSimplifier{}(*m_ast); | ||||
| 				break; | ||||
| 			case 'n': | ||||
| 				(ControlFlowSimplifier{m_dialect})(*m_ast); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user