Yul Optimizer: Simplify start offset of zero-length operations.

This commit is contained in:
Daniel Kirchner 2022-04-06 18:33:42 +02:00
parent fbef27233c
commit e996fe6247
7 changed files with 56 additions and 4 deletions

View File

@ -8,6 +8,7 @@ Language Features:
Compiler Features: Compiler Features:
* Code Generator: More efficient overflow checks for multiplication. * Code Generator: More efficient overflow checks for multiplication.
* Yul Optimizer: Simplify the starting offset of zero-length operations to zero.
Bugfixes: Bugfixes:

View File

@ -411,7 +411,7 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const
return false; return false;
} }
optional<u256> DataFlowAnalyzer::valueOfIdentifier(YulString const& _name) optional<u256> DataFlowAnalyzer::valueOfIdentifier(YulString const& _name) const
{ {
if (AssignedValue const* value = variableValue(_name)) if (AssignedValue const* value = variableValue(_name))
if (Literal const* literal = get_if<Literal>(value->value)) if (Literal const* literal = get_if<Literal>(value->value))

View File

@ -148,7 +148,7 @@ protected:
bool inScope(YulString _variableName) const; bool inScope(YulString _variableName) const;
/// Returns the literal value of the identifier, if it exists. /// Returns the literal value of the identifier, if it exists.
std::optional<u256> valueOfIdentifier(YulString const& _name); std::optional<u256> valueOfIdentifier(YulString const& _name) const;
enum class StoreLoadLocation { enum class StoreLoadLocation {
Memory = 0, Memory = 0,

View File

@ -23,7 +23,11 @@
#include <libyul/optimiser/SimplificationRules.h> #include <libyul/optimiser/SimplificationRules.h>
#include <libyul/optimiser/OptimiserStep.h> #include <libyul/optimiser/OptimiserStep.h>
#include <libyul/optimiser/OptimizerUtilities.h>
#include <libyul/AST.h> #include <libyul/AST.h>
#include <libyul/Utilities.h>
#include <libevmasm/SemanticInformation.h>
using namespace std; using namespace std;
using namespace solidity; using namespace solidity;
@ -44,4 +48,29 @@ void ExpressionSimplifier::visit(Expression& _expression)
[this](YulString _var) { return variableValue(_var); } [this](YulString _var) { return variableValue(_var); }
)) ))
_expression = match->action().toExpression(debugDataOf(_expression)); _expression = match->action().toExpression(debugDataOf(_expression));
if (auto* functionCall = get_if<FunctionCall>(&_expression))
if (optional<evmasm::Instruction> instruction = toEVMInstruction(m_dialect, functionCall->functionName.name))
for (auto op: evmasm::SemanticInformation::readWriteOperations(*instruction))
if (op.startParameter && op.lengthParameter)
{
Expression& startArgument = functionCall->arguments.at(*op.startParameter);
Expression const& lengthArgument = functionCall->arguments.at(*op.lengthParameter);
if (
knownToBeZero(lengthArgument) &&
!knownToBeZero(startArgument) &&
!holds_alternative<FunctionCall>(startArgument)
)
startArgument = Literal{debugDataOf(startArgument), LiteralKind::Number, "0"_yulstring, {}};
}
}
bool ExpressionSimplifier::knownToBeZero(Expression const& _expression) const
{
if (auto const* literal = get_if<Literal>(&_expression))
return valueOfLiteral(*literal) == 0;
else if (auto const* identifier = get_if<Identifier>(&_expression))
return valueOfIdentifier(identifier->name) == 0;
else
return false;
} }

View File

@ -54,6 +54,7 @@ private:
explicit ExpressionSimplifier(Dialect const& _dialect): explicit ExpressionSimplifier(Dialect const& _dialect):
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore) DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore)
{} {}
bool knownToBeZero(Expression const& _expression) const;
}; };
} }

View File

@ -1,5 +1,5 @@
{ {
for {} div(create(0, 1, 0), shl(msize(), 1)) {} for {} div(create(0, 1, 1), shl(msize(), 1)) {}
{ {
} }
} }
@ -10,7 +10,7 @@
// //
// { // {
// { // {
// for { } div(create(0, 1, 0), shl(msize(), 1)) { } // for { } div(create(0, 1, 1), shl(msize(), 1)) { }
// { } // { }
// } // }
// } // }

View File

@ -0,0 +1,21 @@
{
revert(calldataload(0), 0)
revert(call(0,0,0,0,0,0,0), 0)
calldatacopy(calldataload(1), calldataload(2), 0)
return(calldataload(3), 0)
codecopy(calldataload(4), calldataload(5), sub(42,42))
}
// ----
// step: expressionSimplifier
//
// {
// {
// let _1 := 0
// revert(0, _1)
// pop(call(_1, _1, _1, _1, _1, _1, _1))
// revert(0, _1)
// calldatacopy(0, calldataload(2), _1)
// return(0, _1)
// codecopy(0, calldataload(5), 0)
// }
// }