Refactor stack to memory mover in preparation of moving function arguments.

This commit is contained in:
Daniel Kirchner 2020-10-13 12:12:36 +02:00
parent abfa136afb
commit 61a03036fe
2 changed files with 47 additions and 61 deletions

View File

@ -49,6 +49,23 @@ vector<Statement> generateMemoryStore(
}}); }});
return result; return result;
} }
FunctionCall generateMemoryLoad(Dialect const& _dialect, langutil::SourceLocation const& _loc, YulString _mpos)
{
BuiltinFunction const* memoryLoadFunction = _dialect.memoryLoadFunction(_dialect.defaultType);
yulAssert(memoryLoadFunction, "");
return FunctionCall{
_loc,
Identifier{_loc, memoryLoadFunction->name}, {
Literal{
_loc,
LiteralKind::Number,
_mpos,
{}
}
}
};
}
} }
void StackToMemoryMover::run( void StackToMemoryMover::run(
@ -93,29 +110,34 @@ void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition)
void StackToMemoryMover::operator()(Block& _block) void StackToMemoryMover::operator()(Block& _block)
{ {
using OptionalStatements = std::optional<vector<Statement>>; using OptionalStatements = std::optional<vector<Statement>>;
auto containsVariableNeedingEscalation = [&](auto const& _variables) { auto rewriteAssignmentOrVariableDeclaration = [&](
return util::contains_if(_variables, [&](auto const& var) { auto& _stmt,
auto const& _variables
) -> OptionalStatements {
using StatementType = decay_t<decltype(_stmt)>;
if (_stmt.value)
visit(*_stmt.value);
bool leftHandSideNeedsMoving = util::contains_if(_variables, [&](auto const& var) {
return m_memoryOffsetTracker(var.name); return m_memoryOffsetTracker(var.name);
}); });
}; if (!leftHandSideNeedsMoving)
auto rewriteAssignmentOrVariableDeclaration = [&]( return {};
langutil::SourceLocation const& _loc,
auto const& _variables, langutil::SourceLocation loc = _stmt.location;
std::unique_ptr<Expression> _value
) -> std::vector<Statement> {
if (_variables.size() == 1) if (_variables.size() == 1)
{ {
optional<YulString> offset = m_memoryOffsetTracker(_variables.front().name); optional<YulString> offset = m_memoryOffsetTracker(_variables.front().name);
yulAssert(offset, ""); yulAssert(offset, "");
return generateMemoryStore( return generateMemoryStore(
m_context.dialect, m_context.dialect,
_loc, loc,
*offset, *offset,
_value ? *std::move(_value) : Literal{_loc, LiteralKind::Number, "0"_yulstring, {}} _stmt.value ? *std::move(_stmt.value) : Literal{loc, LiteralKind::Number, "0"_yulstring, {}}
); );
} }
VariableDeclaration tempDecl{_loc, {}, std::move(_value)}; VariableDeclaration tempDecl{loc, {}, std::move(_stmt.value)};
vector<Statement> memoryAssignments; vector<Statement> memoryAssignments;
vector<Statement> variableAssignments; vector<Statement> variableAssignments;
for (auto& var: _variables) for (auto& var: _variables)
@ -126,19 +148,14 @@ void StackToMemoryMover::operator()(Block& _block)
if (optional<YulString> offset = m_memoryOffsetTracker(var.name)) if (optional<YulString> offset = m_memoryOffsetTracker(var.name))
memoryAssignments += generateMemoryStore( memoryAssignments += generateMemoryStore(
m_context.dialect, m_context.dialect,
_loc, loc,
*offset, *offset,
Identifier{_loc, tempVarName} Identifier{loc, tempVarName}
); );
else if constexpr (std::is_same_v<std::decay_t<decltype(var)>, Identifier>)
variableAssignments.emplace_back(Assignment{
_loc, { Identifier{var.location, var.name} },
make_unique<Expression>(Identifier{_loc, tempVarName})
});
else else
variableAssignments.emplace_back(VariableDeclaration{ variableAssignments.emplace_back(StatementType{
_loc, {std::move(var)}, loc, {move(var)},
make_unique<Expression>(Identifier{_loc, tempVarName}) make_unique<Expression>(Identifier{loc, tempVarName})
}); });
} }
std::vector<Statement> result; std::vector<Statement> result;
@ -147,65 +164,34 @@ void StackToMemoryMover::operator()(Block& _block)
result += std::move(memoryAssignments); result += std::move(memoryAssignments);
std::reverse(variableAssignments.begin(), variableAssignments.end()); std::reverse(variableAssignments.begin(), variableAssignments.end());
result += std::move(variableAssignments); result += std::move(variableAssignments);
return result; return OptionalStatements{move(result)};
}; };
util::iterateReplacing( util::iterateReplacing(
_block.statements, _block.statements,
[&](Statement& _statement) [&](Statement& _statement)
{ {
auto defaultVisit = [&]() { ASTModifier::visit(_statement); return OptionalStatements{}; };
return std::visit(util::GenericVisitor{ return std::visit(util::GenericVisitor{
[&](Assignment& _assignment) -> OptionalStatements [&](Assignment& _assignment) -> OptionalStatements
{ {
if (!containsVariableNeedingEscalation(_assignment.variableNames)) return rewriteAssignmentOrVariableDeclaration(_assignment, _assignment.variableNames);
return defaultVisit();
visit(*_assignment.value);
return {rewriteAssignmentOrVariableDeclaration(
_assignment.location,
_assignment.variableNames,
std::move(_assignment.value)
)};
}, },
[&](VariableDeclaration& _varDecl) -> OptionalStatements [&](VariableDeclaration& _varDecl) -> OptionalStatements
{ {
if (!containsVariableNeedingEscalation(_varDecl.variables)) return rewriteAssignmentOrVariableDeclaration(_varDecl, _varDecl.variables);
return defaultVisit();
if (_varDecl.value)
visit(*_varDecl.value);
return {rewriteAssignmentOrVariableDeclaration(
_varDecl.location,
_varDecl.variables,
std::move(_varDecl.value)
)};
}, },
[&](auto&) { return defaultVisit(); } [&](auto& _stmt) -> OptionalStatements { (*this)(_stmt); return {}; }
}, _statement); }, _statement);
}); }
);
} }
void StackToMemoryMover::visit(Expression& _expression) void StackToMemoryMover::visit(Expression& _expression)
{ {
ASTModifier::visit(_expression);
if (Identifier* identifier = std::get_if<Identifier>(&_expression)) if (Identifier* identifier = std::get_if<Identifier>(&_expression))
if (optional<YulString> offset = m_memoryOffsetTracker(identifier->name)) if (optional<YulString> offset = m_memoryOffsetTracker(identifier->name))
{ _expression = generateMemoryLoad(m_context.dialect, identifier->location, *offset);
BuiltinFunction const* memoryLoadFunction = m_context.dialect.memoryLoadFunction(m_context.dialect.defaultType);
yulAssert(memoryLoadFunction, "");
langutil::SourceLocation loc = identifier->location;
_expression = FunctionCall{
loc,
Identifier{loc, memoryLoadFunction->name}, {
Literal{
loc,
LiteralKind::Number,
*offset,
{}
}
}
};
return;
}
ASTModifier::visit(_expression);
} }
optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(YulString _variable) const optional<YulString> StackToMemoryMover::VariableMemoryOffsetTracker::operator()(YulString _variable) const

View File

@ -126,7 +126,7 @@ void OptimiserSuite::run(
{ {
yulAssert(_meter, ""); yulAssert(_meter, "");
ConstantOptimiser{*dialect, *_meter}(ast); ConstantOptimiser{*dialect, *_meter}(ast);
if (dialect->providesObjectAccess()) if (dialect->providesObjectAccess() && _optimizeStackAllocation)
StackLimitEvader::run(suite.m_context, _object, CompilabilityChecker{ StackLimitEvader::run(suite.m_context, _object, CompilabilityChecker{
_dialect, _dialect,
_object, _object,