mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #7071 from ethereum/checkAsmDataObject
Check availability of data objects already in analysis phase.
This commit is contained in:
		
						commit
						88477bdb8f
					
				| @ -18,6 +18,7 @@ Compiler Features: | ||||
| 
 | ||||
| Bugfixes: | ||||
|  * View/Pure Checker: Properly detect state variable access through base class. | ||||
|  * Yul analyzer: Check availability of data objects already in analysis phase. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -34,6 +34,7 @@ | ||||
| #include <libyul/backends/evm/EVMDialect.h> | ||||
| #include <libyul/backends/evm/EVMMetrics.h> | ||||
| #include <libyul/optimiser/Suite.h> | ||||
| #include <libyul/Object.h> | ||||
| #include <libyul/YulString.h> | ||||
| 
 | ||||
| #include <liblangutil/ErrorReporter.h> | ||||
| @ -423,23 +424,19 @@ void CompilerContext::appendInlineAssembly( | ||||
| 	{ | ||||
| 		bool const isCreation = m_runtimeContext != nullptr; | ||||
| 		yul::GasMeter meter(dialect, isCreation, _optimiserSettings.expectedExecutionsPerDeployment); | ||||
| 		yul::Object obj; | ||||
| 		obj.code = parserResult; | ||||
| 		obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo); | ||||
| 		yul::OptimiserSuite::run( | ||||
| 			dialect, | ||||
| 			&meter, | ||||
| 			*parserResult, | ||||
| 			analysisInfo, | ||||
| 			obj, | ||||
| 			_optimiserSettings.optimizeStackAllocation, | ||||
| 			externallyUsedIdentifiers | ||||
| 		); | ||||
| 		analysisInfo = yul::AsmAnalysisInfo{}; | ||||
| 		if (!yul::AsmAnalyzer( | ||||
| 			analysisInfo, | ||||
| 			errorReporter, | ||||
| 			boost::none, | ||||
| 			dialect, | ||||
| 			identifierAccess.resolve | ||||
| 		).analyze(*parserResult)) | ||||
| 			reportError("Optimizer introduced error into inline assembly."); | ||||
| 		analysisInfo = std::move(*obj.analysisInfo); | ||||
| 		parserResult = std::move(obj.code); | ||||
| 
 | ||||
| #ifdef SOL_OUTPUT_ASM | ||||
| 		cout << "After optimizer: " << endl; | ||||
| 		cout << yul::AsmPrinter()(*parserResult) << endl; | ||||
|  | ||||
| @ -26,6 +26,7 @@ | ||||
| #include <libyul/AsmAnalysisInfo.h> | ||||
| #include <libyul/Utilities.h> | ||||
| #include <libyul/Exceptions.h> | ||||
| #include <libyul/Object.h> | ||||
| 
 | ||||
| #include <liblangutil/ErrorReporter.h> | ||||
| 
 | ||||
| @ -69,17 +70,19 @@ bool AsmAnalyzer::analyze(Block const& _block) | ||||
| 	return success && !m_errorReporter.hasErrors(); | ||||
| } | ||||
| 
 | ||||
| AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Block const& _ast) | ||||
| AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object) | ||||
| { | ||||
| 	ErrorList errorList; | ||||
| 	langutil::ErrorReporter errors(errorList); | ||||
| 	yul::AsmAnalysisInfo analysisInfo; | ||||
| 	AsmAnalysisInfo analysisInfo; | ||||
| 	bool success = yul::AsmAnalyzer( | ||||
| 		analysisInfo, | ||||
| 		errors, | ||||
| 		Error::Type::SyntaxError, | ||||
| 		_dialect | ||||
| 	).analyze(_ast); | ||||
| 		_dialect, | ||||
| 		{}, | ||||
| 		_object.dataNames() | ||||
| 	).analyze(*_object.code); | ||||
| 	solAssert(success && errorList.empty(), "Invalid assembly/yul code."); | ||||
| 	return analysisInfo; | ||||
| } | ||||
| @ -383,11 +386,19 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) | ||||
| 	{ | ||||
| 		if (!expectExpression(arg)) | ||||
| 			success = false; | ||||
| 		else if (needsLiteralArguments && arg.type() != typeid(Literal)) | ||||
| 			m_errorReporter.typeError( | ||||
| 				_funCall.functionName.location, | ||||
| 				"Function expects direct literals as arguments." | ||||
| 			); | ||||
| 		else if (needsLiteralArguments) | ||||
| 		{ | ||||
| 			if (arg.type() != typeid(Literal)) | ||||
| 				m_errorReporter.typeError( | ||||
| 					_funCall.functionName.location, | ||||
| 					"Function expects direct literals as arguments." | ||||
| 				); | ||||
| 			else if (!m_dataNames.count(boost::get<Literal>(arg).value)) | ||||
| 				m_errorReporter.typeError( | ||||
| 					_funCall.functionName.location, | ||||
| 					"Unknown data object \"" + boost::get<Literal>(arg).value.str() + "\"." | ||||
| 				); | ||||
| 		} | ||||
| 	} | ||||
| 	// Use argument size instead of parameter count to avoid misleading errors.
 | ||||
| 	m_stackHeight += int(returns) - int(_funCall.arguments.size()); | ||||
|  | ||||
| @ -61,13 +61,15 @@ public: | ||||
| 		langutil::ErrorReporter& _errorReporter, | ||||
| 		boost::optional<langutil::Error::Type> _errorTypeForLoose, | ||||
| 		Dialect const& _dialect, | ||||
| 		ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() | ||||
| 		ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver(), | ||||
| 		std::set<YulString> const& _dataNames = {} | ||||
| 	): | ||||
| 		m_resolver(_resolver), | ||||
| 		m_info(_analysisInfo), | ||||
| 		m_errorReporter(_errorReporter), | ||||
| 		m_dialect(_dialect), | ||||
| 		m_errorTypeForLoose(_errorTypeForLoose) | ||||
| 		m_errorTypeForLoose(_errorTypeForLoose), | ||||
| 		m_dataNames(_dataNames) | ||||
| 	{ | ||||
| 		if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect)) | ||||
| 			m_evmVersion = evmDialect->evmVersion(); | ||||
| @ -75,7 +77,9 @@ public: | ||||
| 
 | ||||
| 	bool analyze(Block const& _block); | ||||
| 
 | ||||
| 	static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Block const& _ast); | ||||
| 	/// Performs analysis on the outermost code of the given object and returns the analysis info.
 | ||||
| 	/// Asserts on failure.
 | ||||
| 	static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object); | ||||
| 
 | ||||
| 	bool operator()(Instruction const&); | ||||
| 	bool operator()(Literal const& _literal); | ||||
| @ -124,6 +128,8 @@ private: | ||||
| 	langutil::EVMVersion m_evmVersion; | ||||
| 	Dialect const& m_dialect; | ||||
| 	boost::optional<langutil::Error::Type> m_errorTypeForLoose; | ||||
| 	/// Names of data objects to be referenced by builtin functions with literal arguments.
 | ||||
| 	std::set<YulString> m_dataNames; | ||||
| 	ForLoop const* m_currentForLoop = nullptr; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -113,7 +113,15 @@ bool AssemblyStack::analyzeParsed(Object& _object) | ||||
| { | ||||
| 	solAssert(_object.code, ""); | ||||
| 	_object.analysisInfo = make_shared<AsmAnalysisInfo>(); | ||||
| 	AsmAnalyzer analyzer(*_object.analysisInfo, m_errorReporter, boost::none, languageToDialect(m_language, m_evmVersion)); | ||||
| 
 | ||||
| 	AsmAnalyzer analyzer( | ||||
| 		*_object.analysisInfo, | ||||
| 		m_errorReporter, | ||||
| 		boost::none, | ||||
| 		languageToDialect(m_language, m_evmVersion), | ||||
| 		{}, | ||||
| 		_object.dataNames() | ||||
| 	); | ||||
| 	bool success = analyzer.analyze(*_object.code); | ||||
| 	for (auto& subNode: _object.subObjects) | ||||
| 		if (auto subObject = dynamic_cast<Object*>(subNode.get())) | ||||
| @ -153,8 +161,7 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation) | ||||
| 	OptimiserSuite::run( | ||||
| 		dialect, | ||||
| 		meter.get(), | ||||
| 		*_object.code, | ||||
| 		*_object.analysisInfo, | ||||
| 		_object, | ||||
| 		m_optimiserSettings.optimizeStackAllocation | ||||
| 	); | ||||
| } | ||||
|  | ||||
| @ -34,7 +34,7 @@ using namespace dev; | ||||
| 
 | ||||
| map<YulString, int> CompilabilityChecker::run( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block const& _ast, | ||||
| 	Object const& _object, | ||||
| 	bool _optimizeStackAllocation | ||||
| ) | ||||
| { | ||||
| @ -46,16 +46,26 @@ map<YulString, int> CompilabilityChecker::run( | ||||
| 	if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect)) | ||||
| 	{ | ||||
| 		NoOutputEVMDialect noOutputDialect(*evmDialect); | ||||
| 		BuiltinContext builtinContext; | ||||
| 
 | ||||
| 		yul::AsmAnalysisInfo analysisInfo = | ||||
| 			yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast); | ||||
| 			yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _object); | ||||
| 
 | ||||
| 		BuiltinContext builtinContext; | ||||
| 		builtinContext.currentObject = &_object; | ||||
| 		for (auto name: _object.dataNames()) | ||||
| 			builtinContext.subIDs[name] = 1; | ||||
| 		NoOutputAssembly assembly; | ||||
| 		CodeTransform transform(assembly, analysisInfo, _ast, noOutputDialect, builtinContext, _optimizeStackAllocation); | ||||
| 		CodeTransform transform( | ||||
| 			assembly, | ||||
| 			analysisInfo, | ||||
| 			*_object.code, | ||||
| 			noOutputDialect, | ||||
| 			builtinContext, | ||||
| 			_optimizeStackAllocation | ||||
| 		); | ||||
| 		try | ||||
| 		{ | ||||
| 			transform(_ast); | ||||
| 			transform(*_object.code); | ||||
| 		} | ||||
| 		catch (StackTooDeepError const&) | ||||
| 		{ | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| 
 | ||||
| #include <libyul/Dialect.h> | ||||
| #include <libyul/AsmDataForward.h> | ||||
| #include <libyul/Object.h> | ||||
| 
 | ||||
| #include <map> | ||||
| #include <memory> | ||||
| @ -33,15 +34,18 @@ namespace yul | ||||
|  * Component that checks whether all variables are reachable on the stack and | ||||
|  * returns a mapping from function name to the largest stack difference found | ||||
|  * in that function (no entry present if that function is compilable). | ||||
|  * | ||||
|  * This only works properly if the outermost block is compilable and | ||||
|  * functions are not nested. Otherwise, it might miss reporting some functions. | ||||
|  * | ||||
|  * Only checks the code of the object itself, does not descend into sub-objects. | ||||
|  */ | ||||
| class CompilabilityChecker | ||||
| { | ||||
| public: | ||||
| 	static std::map<YulString, int> run( | ||||
| 		Dialect const& _dialect, | ||||
| 		Block const& _ast, | ||||
| 		Object const& _object, | ||||
| 		bool _optimizeStackAllocation | ||||
| 	); | ||||
| }; | ||||
|  | ||||
| @ -59,3 +59,14 @@ string Object::toString(bool _yul) const | ||||
| 
 | ||||
| 	return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; | ||||
| } | ||||
| 
 | ||||
| set<YulString> Object::dataNames() const | ||||
| { | ||||
| 	set<YulString> names; | ||||
| 	names.insert(name); | ||||
| 	for (auto const& subObject: subIndexByName) | ||||
| 		names.insert(subObject.first); | ||||
| 	// The empty name is not valid
 | ||||
| 	names.erase(YulString{}); | ||||
| 	return names; | ||||
| } | ||||
|  | ||||
| @ -26,6 +26,7 @@ | ||||
| #include <libdevcore/Common.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <set> | ||||
| 
 | ||||
| namespace yul | ||||
| { | ||||
| @ -63,6 +64,10 @@ public: | ||||
| 	/// @returns a (parseable) string representation. Includes types if @a _yul is set.
 | ||||
| 	std::string toString(bool _yul) const override; | ||||
| 
 | ||||
| 	/// @returns the set of names of data objects accessible from within the code of
 | ||||
| 	/// this object.
 | ||||
| 	std::set<YulString> dataNames() const; | ||||
| 
 | ||||
| 	std::shared_ptr<Block> code; | ||||
| 	std::vector<std::shared_ptr<ObjectNode>> subObjects; | ||||
| 	std::map<YulString, size_t> subIndexByName; | ||||
|  | ||||
| @ -553,7 +553,7 @@ Object EVMToEWasmTranslator::run(Object const& _object) | ||||
| 
 | ||||
| 	ErrorList errors; | ||||
| 	ErrorReporter errorReporter(errors); | ||||
| 	AsmAnalyzer analyzer(*ret.analysisInfo, errorReporter, boost::none, WasmDialect::instance()); | ||||
| 	AsmAnalyzer analyzer(*ret.analysisInfo, errorReporter, boost::none, WasmDialect::instance(), {}, _object.dataNames()); | ||||
| 	if (!analyzer.analyze(*ret.code)) | ||||
| 	{ | ||||
| 		// TODO the errors here are "wrong" because they have invalid source references!
 | ||||
|  | ||||
| @ -155,19 +155,20 @@ void eliminateVariables( | ||||
| 
 | ||||
| bool StackCompressor::run( | ||||
| 	Dialect const& _dialect, | ||||
| 	Block& _ast, | ||||
| 	Object& _object, | ||||
| 	bool _optimizeStackAllocation, | ||||
| 	size_t _maxIterations | ||||
| ) | ||||
| { | ||||
| 	yulAssert( | ||||
| 		_ast.statements.size() > 0 && _ast.statements.at(0).type() == typeid(Block), | ||||
| 		_object.code && | ||||
| 		_object.code->statements.size() > 0 && _object.code->statements.at(0).type() == typeid(Block), | ||||
| 		"Need to run the function grouper before the stack compressor." | ||||
| 	); | ||||
| 	bool allowMSizeOptimzation = !SideEffectsCollector(_dialect, _ast).containsMSize(); | ||||
| 	bool allowMSizeOptimzation = !SideEffectsCollector(_dialect, *_object.code).containsMSize(); | ||||
| 	for (size_t iterations = 0; iterations < _maxIterations; iterations++) | ||||
| 	{ | ||||
| 		map<YulString, int> stackSurplus = CompilabilityChecker::run(_dialect, _ast, _optimizeStackAllocation); | ||||
| 		map<YulString, int> stackSurplus = CompilabilityChecker::run(_dialect, _object, _optimizeStackAllocation); | ||||
| 		if (stackSurplus.empty()) | ||||
| 			return true; | ||||
| 
 | ||||
| @ -176,15 +177,15 @@ bool StackCompressor::run( | ||||
| 			yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value."); | ||||
| 			eliminateVariables( | ||||
| 				_dialect, | ||||
| 				boost::get<Block>(_ast.statements.at(0)), | ||||
| 				boost::get<Block>(_object.code->statements.at(0)), | ||||
| 				stackSurplus.at({}), | ||||
| 				allowMSizeOptimzation | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		for (size_t i = 1; i < _ast.statements.size(); ++i) | ||||
| 		for (size_t i = 1; i < _object.code->statements.size(); ++i) | ||||
| 		{ | ||||
| 			FunctionDefinition& fun = boost::get<FunctionDefinition>(_ast.statements[i]); | ||||
| 			FunctionDefinition& fun = boost::get<FunctionDefinition>(_object.code->statements[i]); | ||||
| 			if (!stackSurplus.count(fun.name)) | ||||
| 				continue; | ||||
| 
 | ||||
|  | ||||
| @ -27,13 +27,15 @@ namespace yul | ||||
| { | ||||
| 
 | ||||
| struct Dialect; | ||||
| struct Block; | ||||
| struct Object; | ||||
| struct FunctionDefinition; | ||||
| 
 | ||||
| /**
 | ||||
|  * Optimisation stage that aggressively rematerializes certain variables in a function to free | ||||
|  * space on the stack until it is compilable. | ||||
|  * | ||||
|  * Only runs on the code of the object itself, does not descend into sub-objects. | ||||
|  * | ||||
|  * Prerequisite: Disambiguator, Function Grouper | ||||
|  */ | ||||
| class StackCompressor | ||||
| @ -43,7 +45,7 @@ public: | ||||
| 	/// @returns true if it was successful.
 | ||||
| 	static bool run( | ||||
| 		Dialect const& _dialect, | ||||
| 		Block& _ast, | ||||
| 		Object& _object, | ||||
| 		bool _optimizeStackAllocation, | ||||
| 		size_t _maxIterations | ||||
| 	); | ||||
|  | ||||
| @ -49,6 +49,7 @@ | ||||
| #include <libyul/AsmAnalysisInfo.h> | ||||
| #include <libyul/AsmData.h> | ||||
| #include <libyul/AsmPrinter.h> | ||||
| #include <libyul/Object.h> | ||||
| 
 | ||||
| #include <libyul/backends/wasm/WasmDialect.h> | ||||
| #include <libyul/backends/evm/NoOutputAssembly.h> | ||||
| @ -62,8 +63,7 @@ using namespace yul; | ||||
| void OptimiserSuite::run( | ||||
| 	Dialect const& _dialect, | ||||
| 	GasMeter const* _meter, | ||||
| 	Block& _ast, | ||||
| 	AsmAnalysisInfo const& _analysisInfo, | ||||
| 	Object& _object, | ||||
| 	bool _optimizeStackAllocation, | ||||
| 	set<YulString> const& _externallyUsedIdentifiers | ||||
| ) | ||||
| @ -71,7 +71,12 @@ void OptimiserSuite::run( | ||||
| 	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | ||||
| 	reservedIdentifiers += _dialect.fixedFunctionNames(); | ||||
| 
 | ||||
| 	Block ast = boost::get<Block>(Disambiguator(_dialect, _analysisInfo, reservedIdentifiers)(_ast)); | ||||
| 	*_object.code = boost::get<Block>(Disambiguator( | ||||
| 		_dialect, | ||||
| 		*_object.analysisInfo, | ||||
| 		reservedIdentifiers | ||||
| 	)(*_object.code)); | ||||
| 	Block& ast = *_object.code; | ||||
| 
 | ||||
| 	VarDeclInitializer{}(ast); | ||||
| 	FunctionHoister{}(ast); | ||||
| @ -204,7 +209,12 @@ void OptimiserSuite::run( | ||||
| 	FunctionGrouper{}(ast); | ||||
| 	// We ignore the return value because we will get a much better error
 | ||||
| 	// message once we perform code generation.
 | ||||
| 	StackCompressor::run(_dialect, ast, _optimizeStackAllocation, stackCompressorMaxIterations); | ||||
| 	StackCompressor::run( | ||||
| 		_dialect, | ||||
| 		_object, | ||||
| 		_optimizeStackAllocation, | ||||
| 		stackCompressorMaxIterations | ||||
| 	); | ||||
| 	BlockFlattener{}(ast); | ||||
| 	DeadCodeEliminator{_dialect}(ast); | ||||
| 	ControlFlowSimplifier{_dialect}(ast); | ||||
| @ -224,7 +234,6 @@ void OptimiserSuite::run( | ||||
| 			ast.statements.erase(ast.statements.begin()); | ||||
| 	} | ||||
| 	VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast); | ||||
| 	yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast); | ||||
| 
 | ||||
| 	_ast = std::move(ast); | ||||
| 	*_object.analysisInfo = AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, _object); | ||||
| } | ||||
|  | ||||
| @ -32,9 +32,11 @@ namespace yul | ||||
| struct AsmAnalysisInfo; | ||||
| struct Dialect; | ||||
| class GasMeter; | ||||
| struct Object; | ||||
| 
 | ||||
| /**
 | ||||
|  * Optimiser suite that combines all steps and also provides the settings for the heuristics | ||||
|  * Optimiser suite that combines all steps and also provides the settings for the heuristics. | ||||
|  * Only optimizes the code of the provided object, does not descend into the sub-objects. | ||||
|  */ | ||||
| class OptimiserSuite | ||||
| { | ||||
| @ -42,8 +44,7 @@ public: | ||||
| 	static void run( | ||||
| 		Dialect const& _dialect, | ||||
| 		GasMeter const* _meter, | ||||
| 		Block& _ast, | ||||
| 		AsmAnalysisInfo const& _analysisInfo, | ||||
| 		Object& _object, | ||||
| 		bool _optimizeStackAllocation, | ||||
| 		std::set<YulString> const& _externallyUsedIdentifiers = {} | ||||
| 	); | ||||
|  | ||||
| @ -37,9 +37,10 @@ namespace | ||||
| { | ||||
| string check(string const& _input) | ||||
| { | ||||
| 	shared_ptr<Block> ast = yul::test::parse(_input, false).first; | ||||
| 	BOOST_REQUIRE(ast); | ||||
| 	map<YulString, int> functions = CompilabilityChecker::run(EVMDialect::strictAssemblyForEVM(dev::test::Options::get().evmVersion()), *ast, true); | ||||
| 	Object obj; | ||||
| 	std::tie(obj.code, obj.analysisInfo) = yul::test::parse(_input, false); | ||||
| 	BOOST_REQUIRE(obj.code); | ||||
| 	map<YulString, int> functions = CompilabilityChecker::run(EVMDialect::strictAssemblyForEVM(dev::test::Options::get().evmVersion()), obj, true); | ||||
| 	string out; | ||||
| 	for (auto const& function: functions) | ||||
| 		out += function.first.str() + ": " + to_string(function.second) + " "; | ||||
|  | ||||
| @ -278,6 +278,19 @@ BOOST_AUTO_TEST_CASE(args_to_datacopy_are_arbitrary) | ||||
| 	BOOST_CHECK(successParse(code)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(non_existing_objects) | ||||
| { | ||||
| 	BOOST_CHECK(successParse( | ||||
| 		"object \"main\" { code { pop(datasize(\"main\")) } }" | ||||
| 	)); | ||||
| 	CHECK_ERROR( | ||||
| 		"object \"main\" { code { pop(datasize(\"abc\")) } }", | ||||
| 		TypeError, | ||||
| 		"Unknown data object" | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -574,6 +574,7 @@ BOOST_AUTO_TEST_CASE(builtins_analysis) | ||||
| 	CHECK_ERROR_DIALECT("{ let a, b := builtin(1, 2) }", DeclarationError, "Variable count mismatch: 2 variables and 3 values.", dialect); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -305,7 +305,10 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | ||||
| 		disambiguate(); | ||||
| 		(FunctionGrouper{})(*m_ast); | ||||
| 		size_t maxIterations = 16; | ||||
| 		StackCompressor::run(*m_dialect, *m_ast, true, maxIterations); | ||||
| 		Object obj; | ||||
| 		obj.code = m_ast; | ||||
| 		StackCompressor::run(*m_dialect, obj, true, maxIterations); | ||||
| 		m_ast = obj.code; | ||||
| 		(BlockFlattener{})(*m_ast); | ||||
| 	} | ||||
| 	else if (m_optimizerStep == "wordSizeTransform") | ||||
| @ -318,7 +321,10 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | ||||
| 	else if (m_optimizerStep == "fullSuite") | ||||
| 	{ | ||||
| 		GasMeter meter(dynamic_cast<EVMDialect const&>(*m_dialect), false, 200); | ||||
| 		OptimiserSuite::run(*m_dialect, &meter, *m_ast, *m_analysisInfo, true); | ||||
| 		yul::Object obj; | ||||
| 		obj.code = m_ast; | ||||
| 		obj.analysisInfo = m_analysisInfo; | ||||
| 		OptimiserSuite::run(*m_dialect, &meter, obj, true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|  | ||||
| @ -1,15 +1,18 @@ | ||||
| { | ||||
|     // Arguments to ``datasize`` and ``dataoffset`` need to be | ||||
|     // literals. We cannot simplify their arguments, but we can | ||||
|     // simplify them as a full expression. | ||||
|     // ``datacopy`` does not have this restriction. | ||||
|     let r := "abc" | ||||
|     let a := datasize("abc") | ||||
|     let x := dataoffset("abc") | ||||
|     // should be replaced by a | ||||
|     let y := datasize("abc") | ||||
|     datacopy("abc", x, y) | ||||
|     mstore(a, x) | ||||
| object "main" { | ||||
|     code { | ||||
|         // Arguments to ``datasize`` and ``dataoffset`` need to be | ||||
|         // literals. We cannot simplify their arguments, but we can | ||||
|         // simplify them as a full expression. | ||||
|         // ``datacopy`` does not have this restriction. | ||||
|         let r := "abc" | ||||
|         let a := datasize("abc") | ||||
|         let x := dataoffset("abc") | ||||
|         // should be replaced by a | ||||
|         let y := datasize("abc") | ||||
|         datacopy("abc", x, y) | ||||
|         mstore(a, x) | ||||
|     } | ||||
|     data "abc" "Hello, World!" | ||||
| } | ||||
| // ==== | ||||
| // step: commonSubexpressionEliminator | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| { | ||||
|     // We should never split arguments to ``dataoffset`` | ||||
|     // or ``datasize`` because they need to be literals | ||||
|     let x := dataoffset("abc") | ||||
|     let y := datasize("abc") | ||||
|     // datacopy is fine, though | ||||
|     datacopy(mload(0), mload(1), mload(2)) | ||||
| object "main" { | ||||
|     code { | ||||
|         // We should never split arguments to ``dataoffset`` | ||||
|         // or ``datasize`` because they need to be literals | ||||
|         let x := dataoffset("abc") | ||||
|         let y := datasize("abc") | ||||
|         // datacopy is fine, though | ||||
|         datacopy(mload(0), mload(1), mload(2)) | ||||
|     } | ||||
|     data "abc" "Hello, World!" | ||||
| } | ||||
| // ==== | ||||
| // step: expressionSplitter | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include <libyul/AsmData.h> | ||||
| #include <libyul/AsmParser.h> | ||||
| #include <libyul/AsmPrinter.h> | ||||
| #include <libyul/Object.h> | ||||
| #include <liblangutil/SourceReferenceFormatter.h> | ||||
| 
 | ||||
| #include <libyul/optimiser/BlockFlattener.h> | ||||
| @ -207,8 +208,12 @@ public: | ||||
| 				SSAReverser::run(*m_ast); | ||||
| 				break; | ||||
| 			case 'p': | ||||
| 				StackCompressor::run(m_dialect, *m_ast, true, 16); | ||||
| 			{ | ||||
| 				Object obj; | ||||
| 				obj.code = m_ast; | ||||
| 				StackCompressor::run(m_dialect, obj, true, 16); | ||||
| 				break; | ||||
| 			} | ||||
| 			default: | ||||
| 				cout << "Unknown option." << endl; | ||||
| 			} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user