mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			128 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
	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 <http://www.gnu.org/licenses/>.
 | 
						|
*/
 | 
						|
// SPDX-License-Identifier: GPL-3.0
 | 
						|
/**
 | 
						|
 * UnusedFunctionParameterPruner: Optimiser step that removes unused parameters from function
 | 
						|
 * definition.
 | 
						|
 */
 | 
						|
 | 
						|
#include <libyul/optimiser/UnusedFunctionParameterPruner.h>
 | 
						|
#include <libyul/optimiser/UnusedFunctionsCommon.h>
 | 
						|
#include <libyul/optimiser/OptimiserStep.h>
 | 
						|
#include <libyul/optimiser/NameCollector.h>
 | 
						|
#include <libyul/optimiser/NameDisplacer.h>
 | 
						|
#include <libyul/optimiser/NameDispenser.h>
 | 
						|
#include <libyul/YulString.h>
 | 
						|
#include <libyul/AST.h>
 | 
						|
 | 
						|
#include <libsolutil/CommonData.h>
 | 
						|
 | 
						|
#include <boost/algorithm/cxx11/all_of.hpp>
 | 
						|
 | 
						|
#include <optional>
 | 
						|
#include <variant>
 | 
						|
 | 
						|
using namespace std;
 | 
						|
using namespace solidity::util;
 | 
						|
using namespace solidity::yul;
 | 
						|
using namespace solidity::yul::unusedFunctionsCommon;
 | 
						|
 | 
						|
void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ast)
 | 
						|
{
 | 
						|
	map<YulString, size_t> references = ReferencesCounter::countReferences(_ast);
 | 
						|
	auto used = [&](auto v) -> bool { return references.count(v.name); };
 | 
						|
 | 
						|
	// Function name and a pair of boolean masks, the first corresponds to parameters and the second
 | 
						|
	// corresponds to returnVariables.
 | 
						|
	//
 | 
						|
	// For the first vector in the pair, a value `false` at index `i` indicates that the function
 | 
						|
	// argument at index `i` in `FunctionDefinition::parameters` is unused inside the function body.
 | 
						|
	//
 | 
						|
	// Similarly for the second vector in the pair, a value `false` at index `i` indicates that the
 | 
						|
	// return parameter at index `i` in `FunctionDefinition::returnVariables` is unused inside
 | 
						|
	// function body.
 | 
						|
	map<YulString, pair<vector<bool>, vector<bool>>> usedParametersAndReturnVariables;
 | 
						|
 | 
						|
	// Step 1 of UnusedFunctionParameterPruner: Find functions whose parameters (both arguments and
 | 
						|
	// return-parameters) are not used in its body.
 | 
						|
	for (auto const& statement: _ast.statements)
 | 
						|
		if (holds_alternative<FunctionDefinition>(statement))
 | 
						|
		{
 | 
						|
			FunctionDefinition const& f = std::get<FunctionDefinition>(statement);
 | 
						|
 | 
						|
			if (tooSimpleToBePruned(f) || boost::algorithm::all_of(f.parameters + f.returnVariables, used))
 | 
						|
				continue;
 | 
						|
 | 
						|
			usedParametersAndReturnVariables[f.name] = {
 | 
						|
				applyMap(f.parameters, used),
 | 
						|
				applyMap(f.returnVariables, used)
 | 
						|
			};
 | 
						|
		}
 | 
						|
 | 
						|
	set<YulString> functionNamesToFree = util::keys(usedParametersAndReturnVariables);
 | 
						|
 | 
						|
	// Step 2 of UnusedFunctionParameterPruner: Renames the function and replaces all references to
 | 
						|
	// the function, say `f`, by its new name, say `f_1`.
 | 
						|
	NameDisplacer replace{_context.dispenser, functionNamesToFree};
 | 
						|
	replace(_ast);
 | 
						|
 | 
						|
	// Inverse-Map of the above translations. In the above example, this will store an element with
 | 
						|
	// key `f_1` and value `f`.
 | 
						|
	std::map<YulString, YulString> newToOriginalNames = invertMap(replace.translations());
 | 
						|
 | 
						|
	// Step 3 of UnusedFunctionParameterPruner: introduce a new function in the block with body of
 | 
						|
	// the old one. Replace the body of the old one with a function call to the new one with reduced
 | 
						|
	// parameters.
 | 
						|
	//
 | 
						|
	// For example: introduce a new 'linking' function `f` with the same the body as `f_1`, but with
 | 
						|
	// reduced parameters, i.e., `function f() -> y { y := 1 }`. Now replace the body of `f_1` with
 | 
						|
	// a call to `f`, i.e., `f_1(x) -> y { y := f() }`.
 | 
						|
	iterateReplacing(_ast.statements, [&](Statement& _s) -> optional<vector<Statement>> {
 | 
						|
		if (holds_alternative<FunctionDefinition>(_s))
 | 
						|
		{
 | 
						|
			// The original function except that it has a new name (e.g., `f_1`)
 | 
						|
			FunctionDefinition& originalFunction = get<FunctionDefinition>(_s);
 | 
						|
			if (newToOriginalNames.count(originalFunction.name))
 | 
						|
			{
 | 
						|
 | 
						|
				YulString linkingFunctionName = originalFunction.name;
 | 
						|
				YulString originalFunctionName = newToOriginalNames.at(linkingFunctionName);
 | 
						|
				pair<vector<bool>, vector<bool>> used =
 | 
						|
					usedParametersAndReturnVariables.at(originalFunctionName);
 | 
						|
 | 
						|
				FunctionDefinition linkingFunction = createLinkingFunction(
 | 
						|
					originalFunction,
 | 
						|
					used,
 | 
						|
					originalFunctionName,
 | 
						|
					linkingFunctionName,
 | 
						|
					_context.dispenser
 | 
						|
				);
 | 
						|
 | 
						|
				originalFunction.name = originalFunctionName;
 | 
						|
				originalFunction.parameters =
 | 
						|
					filter(originalFunction.parameters, used.first);
 | 
						|
				originalFunction.returnVariables =
 | 
						|
					filter(originalFunction.returnVariables, used.second);
 | 
						|
 | 
						|
				return make_vector<Statement>(move(originalFunction), move(linkingFunction));
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return nullopt;
 | 
						|
	});
 | 
						|
}
 |