mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Special case code generation for for loops.
This commit is contained in:
parent
cc7a14a61d
commit
d233c66795
@ -30,6 +30,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* Code Generator: Remove redundant overflow checks in specific for loops.
|
||||||
* Commandline Interface: Add ``--ast-compact-json`` output in assembler mode.
|
* Commandline Interface: Add ``--ast-compact-json`` output in assembler mode.
|
||||||
* Commandline Interface: Add ``--ir-ast-json`` and ``--ir-optimized-ast-json`` outputs for Solidity input, providing AST in compact JSON format for IR and optimized IR.
|
* Commandline Interface: Add ``--ir-ast-json`` and ``--ir-optimized-ast-json`` outputs for Solidity input, providing AST in compact JSON format for IR and optimized IR.
|
||||||
* Commandline Interface: Respect ``--optimize-yul`` and ``--no-optimize-yul`` in compiler mode and accept them in assembler mode as well. ``--optimize --no-optimize-yul`` combination now allows enabling EVM assembly optimizer without enabling Yul optimizer.
|
* Commandline Interface: Respect ``--optimize-yul`` and ``--no-optimize-yul`` in compiler mode and accept them in assembler mode as well. ``--optimize --no-optimize-yul`` combination now allows enabling EVM assembly optimizer without enabling Yul optimizer.
|
||||||
|
@ -129,6 +129,17 @@ void PostTypeChecker::endVisit(ModifierInvocation const& _modifierInvocation)
|
|||||||
callEndVisit(_modifierInvocation);
|
callEndVisit(_modifierInvocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PostTypeChecker::visit(ForStatement const& _forStatement)
|
||||||
|
{
|
||||||
|
return callVisit(_forStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostTypeChecker::endVisit(ForStatement const& _forStatement)
|
||||||
|
{
|
||||||
|
callEndVisit(_forStatement);
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
|
struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
|
||||||
@ -421,15 +432,70 @@ struct ReservedErrorSelector: public PostTypeChecker::Checker
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LValueChecker: public ASTConstVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LValueChecker(Identifier const& _identifier): m_declaration(_identifier.annotation().referencedDeclaration) {}
|
||||||
|
bool willBeWrittenTo() const { return m_willBeWrittenTo; }
|
||||||
|
void endVisit(Identifier const& _identifier) override
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
_identifier.annotation().referencedDeclaration == m_declaration &&
|
||||||
|
_identifier.annotation().willBeWrittenTo
|
||||||
|
)
|
||||||
|
m_willBeWrittenTo = true;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Declaration const* m_declaration;
|
||||||
|
bool m_willBeWrittenTo = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SimpleCounterForLoopChecker: public PostTypeChecker::Checker
|
||||||
|
{
|
||||||
|
SimpleCounterForLoopChecker(ErrorReporter& _errorReporter): Checker(_errorReporter) {}
|
||||||
|
bool visit(ForStatement const& _forStatement) override
|
||||||
|
{
|
||||||
|
_forStatement.annotation().isSimpleCounterLoop = isSimpleCounterLoop(_forStatement);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool isSimpleCounterLoop(ForStatement const& _forStatement) const
|
||||||
|
{
|
||||||
|
auto const* cond = dynamic_cast<BinaryOperation const*>(_forStatement.condition());
|
||||||
|
if (!cond || cond->getOperator() != Token::LessThan || cond->userDefinedFunctionType())
|
||||||
|
return false;
|
||||||
|
if (!_forStatement.loopExpression())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto const* post = dynamic_cast<UnaryOperation const*>(&_forStatement.loopExpression()->expression());
|
||||||
|
// This matches both operators ++i and i++
|
||||||
|
if (!post || post->getOperator() != Token::Inc || post->userDefinedFunctionType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto const* lhsIdentifier = dynamic_cast<Identifier const*>(&cond->leftExpression());
|
||||||
|
auto const* lhsType = dynamic_cast<IntegerType const*>(cond->leftExpression().annotation().type);
|
||||||
|
auto const *commonType = dynamic_cast<IntegerType const*>(cond->annotation().commonType);
|
||||||
|
|
||||||
|
if (lhsIdentifier && lhsType && commonType && *lhsType == *commonType)
|
||||||
|
{
|
||||||
|
LValueChecker lValueChecker{*lhsIdentifier};
|
||||||
|
_forStatement.body().accept(lValueChecker);
|
||||||
|
if (!lValueChecker.willBeWrittenTo())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
|
PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
|
||||||
{
|
{
|
||||||
m_checkers.push_back(std::make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter));
|
m_checkers.push_back(make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter));
|
||||||
m_checkers.push_back(std::make_shared<OverrideSpecifierChecker>(_errorReporter));
|
m_checkers.push_back(make_shared<OverrideSpecifierChecker>(_errorReporter));
|
||||||
m_checkers.push_back(std::make_shared<ModifierContextChecker>(_errorReporter));
|
m_checkers.push_back(make_shared<ModifierContextChecker>(_errorReporter));
|
||||||
m_checkers.push_back(std::make_shared<EventOutsideEmitErrorOutsideRevertChecker>(_errorReporter));
|
m_checkers.push_back(make_shared<EventOutsideEmitErrorOutsideRevertChecker>(_errorReporter));
|
||||||
m_checkers.push_back(std::make_shared<NoVariablesInInterfaceChecker>(_errorReporter));
|
m_checkers.push_back(make_shared<NoVariablesInInterfaceChecker>(_errorReporter));
|
||||||
m_checkers.push_back(std::make_shared<ReservedErrorSelector>(_errorReporter));
|
m_checkers.push_back(make_shared<ReservedErrorSelector>(_errorReporter));
|
||||||
|
m_checkers.push_back(make_shared<SimpleCounterForLoopChecker>(_errorReporter));
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,9 @@ private:
|
|||||||
bool visit(ModifierInvocation const& _modifierInvocation) override;
|
bool visit(ModifierInvocation const& _modifierInvocation) override;
|
||||||
void endVisit(ModifierInvocation const& _modifierInvocation) override;
|
void endVisit(ModifierInvocation const& _modifierInvocation) override;
|
||||||
|
|
||||||
|
bool visit(ForStatement const& _forStatement) override;
|
||||||
|
void endVisit(ForStatement const& _forStatement) override;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool callVisit(T const& _node)
|
bool callVisit(T const& _node)
|
||||||
{
|
{
|
||||||
|
@ -238,6 +238,7 @@ struct TryCatchClauseAnnotation: ASTAnnotation, ScopableAnnotation
|
|||||||
|
|
||||||
struct ForStatementAnnotation: StatementAnnotation, ScopableAnnotation
|
struct ForStatementAnnotation: StatementAnnotation, ScopableAnnotation
|
||||||
{
|
{
|
||||||
|
util::SetOnce<bool> isSimpleCounterLoop;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReturnAnnotation: StatementAnnotation
|
struct ReturnAnnotation: StatementAnnotation
|
||||||
|
@ -742,12 +742,18 @@ bool ASTJsonExporter::visit(WhileStatement const& _node)
|
|||||||
|
|
||||||
bool ASTJsonExporter::visit(ForStatement const& _node)
|
bool ASTJsonExporter::visit(ForStatement const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "ForStatement", {
|
|
||||||
std::make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())),
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
std::make_pair("condition", toJsonOrNull(_node.condition())),
|
make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())),
|
||||||
std::make_pair("loopExpression", toJsonOrNull(_node.loopExpression())),
|
make_pair("condition", toJsonOrNull(_node.condition())),
|
||||||
std::make_pair("body", toJson(_node.body()))
|
make_pair("loopExpression", toJsonOrNull(_node.loopExpression())),
|
||||||
});
|
make_pair("body", toJson(_node.body()))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_node.annotation().isSimpleCounterLoop.set())
|
||||||
|
attributes.emplace_back(make_pair("isSimpleCounterLoop", *_node.annotation().isSimpleCounterLoop));
|
||||||
|
|
||||||
|
setJsonNode(_node, "ForStatement", std::move(attributes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1245,7 +1245,16 @@ bool ContractCompiler::visit(ForStatement const& _forStatement)
|
|||||||
|
|
||||||
// for's loop expression if existing
|
// for's loop expression if existing
|
||||||
if (_forStatement.loopExpression())
|
if (_forStatement.loopExpression())
|
||||||
|
{
|
||||||
|
Arithmetic previousArithmetic = m_context.arithmetic();
|
||||||
|
if (
|
||||||
|
*_forStatement.annotation().isSimpleCounterLoop &&
|
||||||
|
m_optimiserSettings == OptimiserSettings::standard()
|
||||||
|
)
|
||||||
|
m_context.setArithmetic(Arithmetic::Wrapping);
|
||||||
_forStatement.loopExpression()->accept(*this);
|
_forStatement.loopExpression()->accept(*this);
|
||||||
|
m_context.setArithmetic(previousArithmetic);
|
||||||
|
}
|
||||||
|
|
||||||
m_context.appendJumpTo(loopStart);
|
m_context.appendJumpTo(loopStart);
|
||||||
|
|
||||||
|
@ -617,7 +617,9 @@ bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
|
|||||||
_forStatement.body(),
|
_forStatement.body(),
|
||||||
_forStatement.condition(),
|
_forStatement.condition(),
|
||||||
_forStatement.initializationExpression(),
|
_forStatement.initializationExpression(),
|
||||||
_forStatement.loopExpression()
|
_forStatement.loopExpression(),
|
||||||
|
false,
|
||||||
|
*_forStatement.annotation().isSimpleCounterLoop
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -3192,7 +3194,8 @@ void IRGeneratorForStatements::generateLoop(
|
|||||||
Expression const* _conditionExpression,
|
Expression const* _conditionExpression,
|
||||||
Statement const* _initExpression,
|
Statement const* _initExpression,
|
||||||
ExpressionStatement const* _loopExpression,
|
ExpressionStatement const* _loopExpression,
|
||||||
bool _isDoWhile
|
bool _isDoWhile,
|
||||||
|
bool _isSimpleCounterLoop
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::string firstRun;
|
std::string firstRun;
|
||||||
@ -3209,7 +3212,13 @@ void IRGeneratorForStatements::generateLoop(
|
|||||||
_initExpression->accept(*this);
|
_initExpression->accept(*this);
|
||||||
appendCode() << "} 1 {\n";
|
appendCode() << "} 1 {\n";
|
||||||
if (_loopExpression)
|
if (_loopExpression)
|
||||||
|
{
|
||||||
|
Arithmetic previousArithmetic = m_context.arithmetic();
|
||||||
|
if (_isSimpleCounterLoop)
|
||||||
|
m_context.setArithmetic(Arithmetic::Wrapping);
|
||||||
_loopExpression->accept(*this);
|
_loopExpression->accept(*this);
|
||||||
|
m_context.setArithmetic(previousArithmetic);
|
||||||
|
}
|
||||||
appendCode() << "}\n";
|
appendCode() << "}\n";
|
||||||
appendCode() << "{\n";
|
appendCode() << "{\n";
|
||||||
|
|
||||||
|
@ -235,7 +235,8 @@ private:
|
|||||||
Expression const* _conditionExpression,
|
Expression const* _conditionExpression,
|
||||||
Statement const* _initExpression = nullptr,
|
Statement const* _initExpression = nullptr,
|
||||||
ExpressionStatement const* _loopExpression = nullptr,
|
ExpressionStatement const* _loopExpression = nullptr,
|
||||||
bool _isDoWhile = false
|
bool _isDoWhile = false,
|
||||||
|
bool _isSimpleCounterLoop = false
|
||||||
);
|
);
|
||||||
|
|
||||||
static Type const& type(Expression const& _expression);
|
static Type const& type(Expression const& _expression);
|
||||||
|
Loading…
Reference in New Issue
Block a user