mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Purge using namespace std from libyul/backends
Signed-off-by: Jun Zhang <jun@junz.org>
This commit is contained in:
parent
37e18612c5
commit
1ebdab43d8
@ -28,7 +28,6 @@
|
||||
|
||||
#include <libsolutil/StackTooDeepString.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include <variant>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -48,9 +47,9 @@ struct MiniEVMInterpreter
|
||||
return std::visit(*this, _expr);
|
||||
}
|
||||
|
||||
u256 eval(evmasm::Instruction _instr, vector<Expression> const& _arguments)
|
||||
u256 eval(evmasm::Instruction _instr, std::vector<Expression> const& _arguments)
|
||||
{
|
||||
vector<u256> args;
|
||||
std::vector<u256> args;
|
||||
for (auto const& arg: _arguments)
|
||||
args.emplace_back(eval(arg));
|
||||
switch (_instr)
|
||||
@ -92,7 +91,7 @@ struct MiniEVMInterpreter
|
||||
|
||||
void ConstantOptimiser::visit(Expression& _e)
|
||||
{
|
||||
if (holds_alternative<Literal>(_e))
|
||||
if (std::holds_alternative<Literal>(_e))
|
||||
{
|
||||
Literal const& literal = std::get<Literal>(_e);
|
||||
if (literal.kind != LiteralKind::Number)
|
||||
@ -115,7 +114,7 @@ Expression const* RepresentationFinder::tryFindRepresentation(u256 const& _value
|
||||
return nullptr;
|
||||
|
||||
Representation const& repr = findRepresentation(_value);
|
||||
if (holds_alternative<Literal>(*repr.expression))
|
||||
if (std::holds_alternative<Literal>(*repr.expression))
|
||||
return nullptr;
|
||||
else
|
||||
return repr.expression.get();
|
||||
@ -180,7 +179,7 @@ Representation const& RepresentationFinder::findRepresentation(u256 const& _valu
|
||||
Representation RepresentationFinder::represent(u256 const& _value) const
|
||||
{
|
||||
Representation repr;
|
||||
repr.expression = make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}});
|
||||
repr.expression = std::make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}});
|
||||
repr.cost = m_meter.costs(*repr.expression);
|
||||
return repr;
|
||||
}
|
||||
@ -191,7 +190,7 @@ Representation RepresentationFinder::represent(
|
||||
) const
|
||||
{
|
||||
Representation repr;
|
||||
repr.expression = make_unique<Expression>(FunctionCall{
|
||||
repr.expression = std::make_unique<Expression>(FunctionCall{
|
||||
m_debugData,
|
||||
Identifier{m_debugData, _instruction},
|
||||
{ASTCopier{}.translate(*_argument.expression)}
|
||||
@ -207,7 +206,7 @@ Representation RepresentationFinder::represent(
|
||||
) const
|
||||
{
|
||||
Representation repr;
|
||||
repr.expression = make_unique<Expression>(FunctionCall{
|
||||
repr.expression = std::make_unique<Expression>(FunctionCall{
|
||||
m_debugData,
|
||||
Identifier{m_debugData, _instruction},
|
||||
{ASTCopier{}.translate(*_arg1.expression), ASTCopier{}.translate(*_arg2.expression)}
|
||||
|
@ -45,7 +45,6 @@
|
||||
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -82,15 +81,15 @@ void cleanUnreachable(CFG& _cfg)
|
||||
/// Sets the ``recursive`` member to ``true`` for all recursive function calls.
|
||||
void markRecursiveCalls(CFG& _cfg)
|
||||
{
|
||||
map<CFG::BasicBlock*, vector<CFG::FunctionCall*>> callsPerBlock;
|
||||
std::map<CFG::BasicBlock*, std::vector<CFG::FunctionCall*>> callsPerBlock;
|
||||
auto const& findCalls = [&](CFG::BasicBlock* _block)
|
||||
{
|
||||
if (auto* calls = util::valueOrNullptr(callsPerBlock, _block))
|
||||
return *calls;
|
||||
vector<CFG::FunctionCall*>& calls = callsPerBlock[_block];
|
||||
std::vector<CFG::FunctionCall*>& calls = callsPerBlock[_block];
|
||||
util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) {
|
||||
for (auto& operation: _block->operations)
|
||||
if (auto* functionCall = get_if<CFG::FunctionCall>(&operation.operation))
|
||||
if (auto* functionCall = std::get_if<CFG::FunctionCall>(&operation.operation))
|
||||
calls.emplace_back(functionCall);
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](CFG::BasicBlock::MainExit const&) {},
|
||||
@ -131,7 +130,7 @@ void markRecursiveCalls(CFG& _cfg)
|
||||
/// Entering such a block means that control flow will never return to a previously visited block.
|
||||
void markStartsOfSubGraphs(CFG& _cfg)
|
||||
{
|
||||
vector<CFG::BasicBlock*> entries;
|
||||
std::vector<CFG::BasicBlock*> entries;
|
||||
entries.emplace_back(_cfg.entry);
|
||||
for (auto&& functionInfo: _cfg.functionInfo | ranges::views::values)
|
||||
entries.emplace_back(functionInfo.entry);
|
||||
@ -141,17 +140,17 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
||||
* Detect bridges following Algorithm 1 in https://arxiv.org/pdf/2108.07346.pdf
|
||||
* and mark the bridge targets as starts of sub-graphs.
|
||||
*/
|
||||
set<CFG::BasicBlock*> visited;
|
||||
map<CFG::BasicBlock*, size_t> disc;
|
||||
map<CFG::BasicBlock*, size_t> low;
|
||||
map<CFG::BasicBlock*, CFG::BasicBlock*> parent;
|
||||
std::set<CFG::BasicBlock*> visited;
|
||||
std::map<CFG::BasicBlock*, size_t> disc;
|
||||
std::map<CFG::BasicBlock*, size_t> low;
|
||||
std::map<CFG::BasicBlock*, CFG::BasicBlock*> parent;
|
||||
size_t time = 0;
|
||||
auto dfs = [&](CFG::BasicBlock* _u, auto _recurse) -> void {
|
||||
visited.insert(_u);
|
||||
disc[_u] = low[_u] = time;
|
||||
time++;
|
||||
|
||||
vector<CFG::BasicBlock*> children = _u->entries;
|
||||
std::vector<CFG::BasicBlock*> children = _u->entries;
|
||||
visit(util::GenericVisitor{
|
||||
[&](CFG::BasicBlock::Jump const& _jump) {
|
||||
children.emplace_back(_jump.target);
|
||||
@ -171,7 +170,7 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
||||
{
|
||||
parent[v] = _u;
|
||||
_recurse(v, _recurse);
|
||||
low[_u] = min(low[_u], low[v]);
|
||||
low[_u] = std::min(low[_u], low[v]);
|
||||
if (low[v] > disc[_u])
|
||||
{
|
||||
// _u <-> v is a cut edge in the undirected graph
|
||||
@ -186,7 +185,7 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
||||
}
|
||||
}
|
||||
else if (v != parent[_u])
|
||||
low[_u] = min(low[_u], disc[v]);
|
||||
low[_u] = std::min(low[_u], disc[v]);
|
||||
};
|
||||
dfs(entry, dfs);
|
||||
}
|
||||
@ -234,7 +233,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
|
||||
ControlFlowGraphBuilder::ControlFlowGraphBuilder(
|
||||
CFG& _graph,
|
||||
AsmAnalysisInfo const& _analysisInfo,
|
||||
map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects,
|
||||
std::map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects,
|
||||
Dialect const& _dialect
|
||||
):
|
||||
m_graph(_graph),
|
||||
@ -271,7 +270,7 @@ void ControlFlowGraphBuilder::operator()(VariableDeclaration const& _varDecl)
|
||||
yulAssert(m_currentBlock, "");
|
||||
auto declaredVariables = _varDecl.variables | ranges::views::transform([&](TypedName const& _var) {
|
||||
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
||||
}) | ranges::to<vector<VariableSlot>>;
|
||||
}) | ranges::to<std::vector<VariableSlot>>;
|
||||
Stack input;
|
||||
if (_varDecl.value)
|
||||
input = visitAssignmentRightHandSide(*_varDecl.value, declaredVariables.size());
|
||||
@ -287,7 +286,7 @@ void ControlFlowGraphBuilder::operator()(Assignment const& _assignment)
|
||||
{
|
||||
auto assignedVariables = _assignment.variableNames | ranges::views::transform([&](Identifier const& _var) {
|
||||
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
||||
}) | ranges::to<vector<VariableSlot>>;
|
||||
}) | ranges::to<std::vector<VariableSlot>>;
|
||||
|
||||
Stack input = visitAssignmentRightHandSide(*_assignment.value, assignedVariables.size());
|
||||
yulAssert(m_currentBlock);
|
||||
@ -314,7 +313,7 @@ void ControlFlowGraphBuilder::operator()(Block const& _block)
|
||||
{
|
||||
ScopedSaveAndRestore saveScope(m_scope, m_info.scopes.at(&_block).get());
|
||||
for (auto const& statement: _block.statements)
|
||||
if (auto const* function = get_if<FunctionDefinition>(&statement))
|
||||
if (auto const* function = std::get_if<FunctionDefinition>(&statement))
|
||||
registerFunction(*function);
|
||||
for (auto const& statement: _block.statements)
|
||||
std::visit(*this, statement);
|
||||
@ -334,10 +333,10 @@ void ControlFlowGraphBuilder::operator()(If const& _if)
|
||||
void ControlFlowGraphBuilder::operator()(Switch const& _switch)
|
||||
{
|
||||
yulAssert(m_currentBlock, "");
|
||||
shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch);
|
||||
std::shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch);
|
||||
|
||||
auto ghostVariableId = m_graph.ghostVariables.size();
|
||||
YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]");
|
||||
YulString ghostVariableName("GHOST[" + std::to_string(ghostVariableId) + "]");
|
||||
auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName});
|
||||
|
||||
// Artificially generate:
|
||||
@ -394,12 +393,12 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch)
|
||||
|
||||
void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
|
||||
{
|
||||
shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop);
|
||||
std::shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop);
|
||||
ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get());
|
||||
(*this)(_loop.pre);
|
||||
|
||||
std::optional<bool> constantCondition;
|
||||
if (auto const* literalCondition = get_if<yul::Literal>(_loop.condition.get()))
|
||||
if (auto const* literalCondition = std::get_if<yul::Literal>(_loop.condition.get()))
|
||||
constantCondition = valueOfLiteral(*literalCondition) != 0;
|
||||
|
||||
CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition));
|
||||
@ -497,13 +496,13 @@ void ControlFlowGraphBuilder::registerFunction(FunctionDefinition const& _functi
|
||||
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)),
|
||||
_param.debugData
|
||||
};
|
||||
}) | ranges::to<vector>,
|
||||
}) | ranges::to<std::vector>,
|
||||
_functionDefinition.returnVariables | ranges::views::transform([&](auto const& _retVar) {
|
||||
return VariableSlot{
|
||||
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_retVar.name)),
|
||||
_retVar.debugData
|
||||
};
|
||||
}) | ranges::to<vector>,
|
||||
}) | ranges::to<std::vector>,
|
||||
{},
|
||||
m_functionSideEffects.at(&_functionDefinition).canContinue
|
||||
})).second;
|
||||
@ -609,7 +608,7 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name)
|
||||
}
|
||||
|
||||
void ControlFlowGraphBuilder::makeConditionalJump(
|
||||
shared_ptr<DebugData const> _debugData,
|
||||
std::shared_ptr<DebugData const> _debugData,
|
||||
StackSlot _condition,
|
||||
CFG::BasicBlock& _nonZero,
|
||||
CFG::BasicBlock& _zero
|
||||
@ -628,7 +627,7 @@ void ControlFlowGraphBuilder::makeConditionalJump(
|
||||
}
|
||||
|
||||
void ControlFlowGraphBuilder::jump(
|
||||
shared_ptr<DebugData const> _debugData,
|
||||
std::shared_ptr<DebugData const> _debugData,
|
||||
CFG::BasicBlock& _target,
|
||||
bool backwards
|
||||
)
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -56,9 +55,9 @@ CodeTransform::CodeTransform(
|
||||
BuiltinContext& _builtinContext,
|
||||
ExternalIdentifierAccess::CodeGenerator _identifierAccessCodeGen,
|
||||
UseNamedLabels _useNamedLabelsForFunctions,
|
||||
shared_ptr<Context> _context,
|
||||
vector<TypedName> _delayedReturnVariables,
|
||||
optional<AbstractAssembly::LabelID> _functionExitLabel
|
||||
std::shared_ptr<Context> _context,
|
||||
std::vector<TypedName> _delayedReturnVariables,
|
||||
std::optional<AbstractAssembly::LabelID> _functionExitLabel
|
||||
):
|
||||
m_assembly(_assembly),
|
||||
m_info(_analysisInfo),
|
||||
@ -74,7 +73,7 @@ CodeTransform::CodeTransform(
|
||||
if (!m_context)
|
||||
{
|
||||
// initialize
|
||||
m_context = make_shared<Context>();
|
||||
m_context = std::make_shared<Context>();
|
||||
if (m_allowStackOpt)
|
||||
m_context->variableReferences = VariableReferenceCounter::run(m_info, _block);
|
||||
}
|
||||
@ -103,7 +102,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
||||
return;
|
||||
|
||||
for (auto const& identifier: m_scope->identifiers)
|
||||
if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second))
|
||||
if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second))
|
||||
if (m_variablesScheduledForDeletion.count(var))
|
||||
deleteVariable(*var);
|
||||
// Directly in a function body block, we can also delete the function arguments,
|
||||
@ -112,7 +111,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
||||
// effect, so we only do it before that.
|
||||
if (!returnVariablesAndFunctionExitAreSetup() && !m_scope->functionScope && m_scope->superScope && m_scope->superScope->functionScope)
|
||||
for (auto const& identifier: m_scope->superScope->identifiers)
|
||||
if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second))
|
||||
if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second))
|
||||
if (m_variablesScheduledForDeletion.count(var))
|
||||
deleteVariable(*var);
|
||||
|
||||
@ -317,7 +316,7 @@ void CodeTransform::operator()(Switch const& _switch)
|
||||
{
|
||||
visitExpression(*_switch.expression);
|
||||
int expressionHeight = m_assembly.stackHeight();
|
||||
map<Case const*, AbstractAssembly::LabelID> caseBodies;
|
||||
std::map<Case const*, AbstractAssembly::LabelID> caseBodies;
|
||||
AbstractAssembly::LabelID end = m_assembly.newLabelId();
|
||||
for (Case const& c: _switch.cases)
|
||||
{
|
||||
@ -447,7 +446,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
|
||||
// This vector holds the desired target positions of all stack slots and is
|
||||
// modified parallel to the actual stack.
|
||||
vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1);
|
||||
std::vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1);
|
||||
stackLayout[0] = static_cast<int>(_function.returnVariables.size()); // Move return label to the top
|
||||
for (auto&& [n, returnVariable]: ranges::views::enumerate(_function.returnVariables))
|
||||
stackLayout.at(m_context->variableStackHeights.at(
|
||||
@ -463,7 +462,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
"The function " +
|
||||
_function.name.str() +
|
||||
" has " +
|
||||
to_string(stackLayout.size() - 17) +
|
||||
std::to_string(stackLayout.size() - 17) +
|
||||
" parameters or return variables too many to fit the stack size."
|
||||
);
|
||||
stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size()));
|
||||
@ -479,7 +478,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
else
|
||||
{
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u));
|
||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||
std::swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||
}
|
||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
|
||||
@ -571,7 +570,7 @@ void CodeTransform::operator()(Block const& _block)
|
||||
m_scope = m_info.scopes.at(&_block).get();
|
||||
|
||||
for (auto const& statement: _block.statements)
|
||||
if (auto function = get_if<FunctionDefinition>(&statement))
|
||||
if (auto function = std::get_if<FunctionDefinition>(&statement))
|
||||
createFunctionEntryID(*function);
|
||||
|
||||
int blockStartStackHeight = m_assembly.stackHeight();
|
||||
@ -579,7 +578,7 @@ void CodeTransform::operator()(Block const& _block)
|
||||
|
||||
bool isOutermostFunctionBodyBlock = m_scope && m_scope->superScope && m_scope->superScope->functionScope;
|
||||
bool performValidation = !m_allowStackOpt || !isOutermostFunctionBodyBlock;
|
||||
finalizeBlock(_block, performValidation ? make_optional(blockStartStackHeight) : nullopt);
|
||||
finalizeBlock(_block, performValidation ? std::make_optional(blockStartStackHeight) : std::nullopt);
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
@ -588,7 +587,7 @@ void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function)
|
||||
Scope::Function& scopeFunction = std::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
||||
yulAssert(!m_context->functionEntryIDs.count(&scopeFunction), "");
|
||||
|
||||
optional<size_t> astID;
|
||||
std::optional<size_t> astID;
|
||||
if (_function.debugData)
|
||||
astID = _function.debugData->astID;
|
||||
|
||||
@ -659,16 +658,16 @@ void CodeTransform::setupReturnVariablesAndFunctionExit()
|
||||
namespace
|
||||
{
|
||||
|
||||
bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<TypedName> const& _returnVariables)
|
||||
bool statementNeedsReturnVariableSetup(Statement const& _statement, std::vector<TypedName> const& _returnVariables)
|
||||
{
|
||||
if (holds_alternative<FunctionDefinition>(_statement))
|
||||
if (std::holds_alternative<FunctionDefinition>(_statement))
|
||||
return true;
|
||||
if (
|
||||
holds_alternative<ExpressionStatement>(_statement) ||
|
||||
holds_alternative<Assignment>(_statement)
|
||||
std::holds_alternative<ExpressionStatement>(_statement) ||
|
||||
std::holds_alternative<Assignment>(_statement)
|
||||
)
|
||||
{
|
||||
map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement);
|
||||
std::map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement);
|
||||
auto isReferenced = [&references](TypedName const& _returnVariable) {
|
||||
return references.count(_returnVariable.name);
|
||||
};
|
||||
@ -680,7 +679,7 @@ bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<Typed
|
||||
|
||||
}
|
||||
|
||||
void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
||||
void CodeTransform::visitStatements(std::vector<Statement> const& _statements)
|
||||
{
|
||||
std::optional<AbstractAssembly::LabelID> jumpTarget = std::nullopt;
|
||||
|
||||
@ -716,7 +715,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
||||
freeUnusedVariables();
|
||||
}
|
||||
|
||||
void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartStackHeight)
|
||||
void CodeTransform::finalizeBlock(Block const& _block, std::optional<int> blockStartStackHeight)
|
||||
{
|
||||
m_assembly.setSourceLocation(originLocationOf(_block));
|
||||
|
||||
@ -725,7 +724,7 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS
|
||||
// pop variables
|
||||
yulAssert(m_info.scopes.at(&_block).get() == m_scope, "");
|
||||
for (auto const& id: m_scope->identifiers)
|
||||
if (holds_alternative<Scope::Variable>(id.second))
|
||||
if (std::holds_alternative<Scope::Variable>(id.second))
|
||||
{
|
||||
Scope::Variable const& var = std::get<Scope::Variable>(id.second);
|
||||
if (m_allowStackOpt)
|
||||
@ -740,11 +739,11 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS
|
||||
if (blockStartStackHeight)
|
||||
{
|
||||
int deposit = m_assembly.stackHeight() - *blockStartStackHeight;
|
||||
yulAssert(deposit == 0, "Invalid stack height at end of block: " + to_string(deposit));
|
||||
yulAssert(deposit == 0, "Invalid stack height at end of block: " + std::to_string(deposit));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeTransform::generateMultiAssignment(vector<Identifier> const& _variableNames)
|
||||
void CodeTransform::generateMultiAssignment(std::vector<Identifier> const& _variableNames)
|
||||
{
|
||||
yulAssert(m_scope, "");
|
||||
for (auto const& variableName: _variableNames | ranges::views::reverse)
|
||||
@ -786,7 +785,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString
|
||||
"Variable " +
|
||||
_varName.str() +
|
||||
" is " +
|
||||
to_string(heightDiff - limit) +
|
||||
std::to_string(heightDiff - limit) +
|
||||
" slot(s) too deep inside the stack. " +
|
||||
stackTooDeepString
|
||||
);
|
||||
@ -798,7 +797,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString
|
||||
|
||||
int CodeTransform::variableStackHeight(YulString _name) const
|
||||
{
|
||||
Scope::Variable const* var = get_if<Scope::Variable>(m_scope->lookup(_name));
|
||||
Scope::Variable const* var = std::get_if<Scope::Variable>(m_scope->lookup(_name));
|
||||
yulAssert(var, "");
|
||||
return static_cast<int>(m_context->variableStackHeights.at(var));
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::string_literals;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -46,9 +46,9 @@ using namespace solidity::util;
|
||||
namespace
|
||||
{
|
||||
|
||||
pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
std::pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
langutil::EVMVersion _evmVersion,
|
||||
string const& _name,
|
||||
std::string const& _name,
|
||||
evmasm::Instruction _instruction
|
||||
)
|
||||
{
|
||||
@ -87,12 +87,12 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||
return {name, std::move(f)};
|
||||
}
|
||||
|
||||
pair<YulString, BuiltinFunctionForEVM> createFunction(
|
||||
string _name,
|
||||
std::pair<YulString, BuiltinFunctionForEVM> createFunction(
|
||||
std::string _name,
|
||||
size_t _params,
|
||||
size_t _returns,
|
||||
SideEffects _sideEffects,
|
||||
vector<optional<LiteralKind>> _literalArguments,
|
||||
std::vector<std::optional<LiteralKind>> _literalArguments,
|
||||
std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&)> _generateCode
|
||||
)
|
||||
{
|
||||
@ -111,7 +111,7 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
|
||||
return {name, f};
|
||||
}
|
||||
|
||||
set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||
std::set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||
{
|
||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||
// basefee for VMs before london.
|
||||
@ -122,20 +122,20 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||
|
||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||
// prevrandao for VMs before paris.
|
||||
auto prevRandaoException = [&](string const& _instrName) -> bool
|
||||
auto prevRandaoException = [&](std::string const& _instrName) -> bool
|
||||
{
|
||||
// Using string comparison as the opcode is the same as for "difficulty"
|
||||
return _instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris();
|
||||
};
|
||||
|
||||
set<YulString> reserved;
|
||||
std::set<YulString> reserved;
|
||||
for (auto const& instr: evmasm::c_instructions)
|
||||
{
|
||||
string name = toLower(instr.first);
|
||||
std::string name = toLower(instr.first);
|
||||
if (!baseFeeException(instr.second) && !prevRandaoException(name))
|
||||
reserved.emplace(name);
|
||||
}
|
||||
reserved += vector<YulString>{
|
||||
reserved += std::vector<YulString>{
|
||||
"linkersymbol"_yulstring,
|
||||
"datasize"_yulstring,
|
||||
"dataoffset"_yulstring,
|
||||
@ -146,19 +146,19 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||
return reserved;
|
||||
}
|
||||
|
||||
map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
||||
std::map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
||||
{
|
||||
|
||||
// Exclude prevrandao as builtin for VMs before paris and difficulty for VMs after paris.
|
||||
auto prevRandaoException = [&](string const& _instrName) -> bool
|
||||
auto prevRandaoException = [&](std::string const& _instrName) -> bool
|
||||
{
|
||||
return (_instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris()) || (_instrName == "difficulty" && _evmVersion >= langutil::EVMVersion::paris());
|
||||
};
|
||||
|
||||
map<YulString, BuiltinFunctionForEVM> builtins;
|
||||
std::map<YulString, BuiltinFunctionForEVM> builtins;
|
||||
for (auto const& instr: evmasm::c_instructions)
|
||||
{
|
||||
string name = toLower(instr.first);
|
||||
std::string name = toLower(instr.first);
|
||||
auto const opcode = instr.second;
|
||||
|
||||
if (
|
||||
@ -198,7 +198,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
BuiltinContext&
|
||||
) {
|
||||
yulAssert(_call.arguments.size() == 1, "");
|
||||
Literal const* literal = get_if<Literal>(&_call.arguments.front());
|
||||
Literal const* literal = std::get_if<Literal>(&_call.arguments.front());
|
||||
yulAssert(literal, "");
|
||||
_assembly.appendConstant(valueOfLiteral(*literal));
|
||||
})
|
||||
@ -217,10 +217,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
_assembly.appendAssemblySize();
|
||||
else
|
||||
{
|
||||
vector<size_t> subIdPath =
|
||||
std::vector<size_t> subIdPath =
|
||||
_context.subIDs.count(dataName) == 0 ?
|
||||
_context.currentObject->pathToSubObject(dataName) :
|
||||
vector<size_t>{_context.subIDs.at(dataName)};
|
||||
std::vector<size_t>{_context.subIDs.at(dataName)};
|
||||
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
||||
_assembly.appendDataSize(subIdPath);
|
||||
}
|
||||
@ -238,10 +238,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
_assembly.appendConstant(0);
|
||||
else
|
||||
{
|
||||
vector<size_t> subIdPath =
|
||||
std::vector<size_t> subIdPath =
|
||||
_context.subIDs.count(dataName) == 0 ?
|
||||
_context.currentObject->pathToSubObject(dataName) :
|
||||
vector<size_t>{_context.subIDs.at(dataName)};
|
||||
std::vector<size_t>{_context.subIDs.at(dataName)};
|
||||
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
||||
_assembly.appendDataOffset(subIdPath);
|
||||
}
|
||||
@ -295,9 +295,9 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
||||
return builtins;
|
||||
}
|
||||
|
||||
regex const& verbatimPattern()
|
||||
std::regex const& verbatimPattern()
|
||||
{
|
||||
regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"};
|
||||
std::regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"};
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const
|
||||
{
|
||||
if (m_objectAccess)
|
||||
{
|
||||
smatch match;
|
||||
std::smatch match;
|
||||
if (regex_match(_name.str(), match, verbatimPattern()))
|
||||
return verbatimFunction(stoul(match[1]), stoul(match[2]));
|
||||
}
|
||||
@ -337,19 +337,19 @@ bool EVMDialect::reservedIdentifier(YulString _name) const
|
||||
|
||||
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(_version, false);
|
||||
dialects[_version] = std::make_unique<EVMDialect>(_version, false);
|
||||
return *dialects[_version];
|
||||
}
|
||||
|
||||
EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialect>(_version, true);
|
||||
dialects[_version] = std::make_unique<EVMDialect>(_version, true);
|
||||
return *dialects[_version];
|
||||
}
|
||||
|
||||
@ -374,16 +374,16 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio
|
||||
|
||||
BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, size_t _returnVariables) const
|
||||
{
|
||||
pair<size_t, size_t> key{_arguments, _returnVariables};
|
||||
shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key];
|
||||
std::pair<size_t, size_t> key{_arguments, _returnVariables};
|
||||
std::shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key];
|
||||
if (!function)
|
||||
{
|
||||
BuiltinFunctionForEVM builtinFunction = createFunction(
|
||||
"verbatim_" + to_string(_arguments) + "i_" + to_string(_returnVariables) + "o",
|
||||
"verbatim_" + std::to_string(_arguments) + "i_" + std::to_string(_returnVariables) + "o",
|
||||
1 + _arguments,
|
||||
_returnVariables,
|
||||
SideEffects::worst(),
|
||||
vector<optional<LiteralKind>>{LiteralKind::String} + vector<optional<LiteralKind>>(_arguments),
|
||||
std::vector<std::optional<LiteralKind>>{LiteralKind::String} + std::vector<std::optional<LiteralKind>>(_arguments),
|
||||
[=](
|
||||
FunctionCall const& _call,
|
||||
AbstractAssembly& _assembly,
|
||||
@ -400,7 +400,7 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz
|
||||
}
|
||||
).second;
|
||||
builtinFunction.isMSize = true;
|
||||
function = make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction));
|
||||
function = std::make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction));
|
||||
}
|
||||
return function.get();
|
||||
}
|
||||
@ -501,9 +501,9 @@ BuiltinFunctionForEVM const* EVMDialectTyped::equalityFunction(YulString _type)
|
||||
|
||||
EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version)
|
||||
{
|
||||
static map<langutil::EVMVersion, unique_ptr<EVMDialectTyped const>> dialects;
|
||||
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialectTyped const>> dialects;
|
||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||
if (!dialects[_version])
|
||||
dialects[_version] = make_unique<EVMDialectTyped>(_version, true);
|
||||
dialects[_version] = std::make_unique<EVMDialectTyped>(_version, true);
|
||||
return *dialects[_version];
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -52,7 +51,7 @@ bigint GasMeter::combineCosts(std::pair<bigint, bigint> _costs) const
|
||||
}
|
||||
|
||||
|
||||
pair<bigint, bigint> GasMeterVisitor::costs(
|
||||
std::pair<bigint, bigint> GasMeterVisitor::costs(
|
||||
Expression const& _expression,
|
||||
EVMDialect const& _dialect,
|
||||
bool _isCreation
|
||||
@ -63,7 +62,7 @@ pair<bigint, bigint> GasMeterVisitor::costs(
|
||||
return {gmv.m_runGas, gmv.m_dataGas};
|
||||
}
|
||||
|
||||
pair<bigint, bigint> GasMeterVisitor::instructionCosts(
|
||||
std::pair<bigint, bigint> GasMeterVisitor::instructionCosts(
|
||||
evmasm::Instruction _instruction,
|
||||
EVMDialect const& _dialect,
|
||||
bool _isCreation
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace solidity::yul;
|
||||
using namespace std;
|
||||
|
||||
void EVMObjectCompiler::compile(
|
||||
Object& _object,
|
||||
@ -91,12 +90,12 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
|
||||
);
|
||||
if (!stackErrors.empty())
|
||||
{
|
||||
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
||||
std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
||||
*_object.code,
|
||||
"memoryguard"_yulstring
|
||||
);
|
||||
auto stackError = stackErrors.front();
|
||||
string msg = stackError.comment() ? *stackError.comment() : "";
|
||||
std::string msg = stackError.comment() ? *stackError.comment() : "";
|
||||
if (memoryGuardCalls.empty())
|
||||
msg += "\nNo memoryguard was present. "
|
||||
"Consider using memory-safe assembly only and annotating it via "
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -122,14 +121,14 @@ void EthAssemblyAdapter::appendAssemblySize()
|
||||
m_assembly.appendProgramSize();
|
||||
}
|
||||
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name)
|
||||
std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, std::string _name)
|
||||
{
|
||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))};
|
||||
std::shared_ptr<evmasm::Assembly> assembly{std::make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))};
|
||||
auto sub = m_assembly.newSub(assembly);
|
||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||
return {std::make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const& _subPath)
|
||||
void EthAssemblyAdapter::appendDataOffset(std::vector<AbstractAssembly::SubID> const& _subPath)
|
||||
{
|
||||
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
||||
{
|
||||
@ -141,7 +140,7 @@ void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const&
|
||||
m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath));
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendDataSize(vector<AbstractAssembly::SubID> const& _subPath)
|
||||
void EthAssemblyAdapter::appendDataSize(std::vector<AbstractAssembly::SubID> const& _subPath)
|
||||
{
|
||||
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
||||
{
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
#include <range/v3/view/iota.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
@ -60,12 +59,12 @@ NoOutputAssembly::LabelID NoOutputAssembly::newLabelId()
|
||||
return 1;
|
||||
}
|
||||
|
||||
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&, size_t, size_t, optional<size_t>)
|
||||
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(std::string const&, size_t, size_t, std::optional<size_t>)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendLinkerSymbol(string const&)
|
||||
void NoOutputAssembly::appendLinkerSymbol(std::string const&)
|
||||
{
|
||||
yulAssert(false, "Linker symbols not yet implemented.");
|
||||
}
|
||||
@ -98,7 +97,7 @@ void NoOutputAssembly::appendAssemblySize()
|
||||
appendInstruction(evmasm::Instruction::PUSH1);
|
||||
}
|
||||
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
|
||||
std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
|
||||
{
|
||||
yulAssert(false, "Sub assemblies not implemented.");
|
||||
return {};
|
||||
|
@ -38,9 +38,8 @@
|
||||
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace std;
|
||||
|
||||
vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||
std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||
AbstractAssembly& _assembly,
|
||||
AsmAnalysisInfo& _analysisInfo,
|
||||
Block const& _block,
|
||||
@ -81,7 +80,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
|
||||
// Assert that we got the correct return label on stack.
|
||||
if (_call.canContinue)
|
||||
{
|
||||
auto const* returnLabelSlot = get_if<FunctionCallReturnLabelSlot>(
|
||||
auto const* returnLabelSlot = std::get_if<FunctionCallReturnLabelSlot>(
|
||||
&m_stack.at(m_stack.size() - _call.functionCall.get().arguments.size() - 1)
|
||||
);
|
||||
yulAssert(returnLabelSlot && &returnLabelSlot->call.get() == &_call.functionCall.get(), "");
|
||||
@ -160,7 +159,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::Assignment const& _assignment)
|
||||
|
||||
// Invalidate occurrences of the assigned variables.
|
||||
for (auto& currentSlot: m_stack)
|
||||
if (VariableSlot const* varSlot = get_if<VariableSlot>(¤tSlot))
|
||||
if (VariableSlot const* varSlot = std::get_if<VariableSlot>(¤tSlot))
|
||||
if (util::contains(_assignment.variables, *varSlot))
|
||||
currentSlot = JunkSlot{};
|
||||
|
||||
@ -185,8 +184,8 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
|
||||
m_dfg(_dfg),
|
||||
m_stackLayout(_stackLayout),
|
||||
m_functionLabels([&](){
|
||||
map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels;
|
||||
set<YulString> assignedFunctionNames;
|
||||
std::map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels;
|
||||
std::set<YulString> assignedFunctionNames;
|
||||
for (Scope::Function const* function: m_dfg.functions)
|
||||
{
|
||||
CFG::FunctionInfo const& functionInfo = m_dfg.functionInfo.at(function);
|
||||
@ -199,7 +198,7 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
|
||||
function->name.str(),
|
||||
function->arguments.size(),
|
||||
function->returns.size(),
|
||||
functionInfo.debugData ? functionInfo.debugData->astID : nullopt
|
||||
functionInfo.debugData ? functionInfo.debugData->astID : std::nullopt
|
||||
) :
|
||||
m_assembly.newLabelId();
|
||||
}
|
||||
@ -212,7 +211,7 @@ void OptimizedEVMCodeTransform::assertLayoutCompatibility(Stack const& _currentS
|
||||
{
|
||||
yulAssert(_currentStack.size() == _desiredStack.size(), "");
|
||||
for (auto&& [currentSlot, desiredSlot]: ranges::zip_view(_currentStack, _desiredStack))
|
||||
yulAssert(holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, "");
|
||||
yulAssert(std::holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, "");
|
||||
}
|
||||
|
||||
AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function)
|
||||
@ -224,15 +223,15 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression
|
||||
{
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](yul::Literal const& _literal) {
|
||||
auto* literalSlot = get_if<LiteralSlot>(&_slot);
|
||||
auto* literalSlot = std::get_if<LiteralSlot>(&_slot);
|
||||
yulAssert(literalSlot && valueOfLiteral(_literal) == literalSlot->value, "");
|
||||
},
|
||||
[&](yul::Identifier const& _identifier) {
|
||||
auto* variableSlot = get_if<VariableSlot>(&_slot);
|
||||
auto* variableSlot = std::get_if<VariableSlot>(&_slot);
|
||||
yulAssert(variableSlot && variableSlot->variable.get().name == _identifier.name, "");
|
||||
},
|
||||
[&](yul::FunctionCall const& _call) {
|
||||
auto* temporarySlot = get_if<TemporarySlot>(&_slot);
|
||||
auto* temporarySlot = std::get_if<TemporarySlot>(&_slot);
|
||||
yulAssert(temporarySlot && &temporarySlot->call.get() == &_call && temporarySlot->index == 0, "");
|
||||
}
|
||||
}, _expression);
|
||||
@ -267,10 +266,10 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
||||
StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
|
||||
YulString varNameDeep = slotVariableName(deepSlot);
|
||||
YulString varNameTop = slotVariableName(m_stack.back());
|
||||
string msg =
|
||||
std::string msg =
|
||||
"Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) +
|
||||
" with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) +
|
||||
": too deep in the stack by " + to_string(deficit) + " slots in " + stackToString(m_stack);
|
||||
": too deep in the stack by " + std::to_string(deficit) + " slots in " + stackToString(m_stack);
|
||||
m_stackErrors.emplace_back(StackTooDeepError(
|
||||
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
||||
varNameDeep.empty() ? varNameTop : varNameDeep,
|
||||
@ -297,9 +296,9 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
||||
{
|
||||
int deficit = static_cast<int>(*depth - 15);
|
||||
YulString varName = slotVariableName(_slot);
|
||||
string msg =
|
||||
std::string msg =
|
||||
(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
|
||||
+ " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
|
||||
+ " is " + std::to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
|
||||
m_stackErrors.emplace_back(StackTooDeepError(
|
||||
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
||||
varName,
|
||||
@ -503,9 +502,9 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
|
||||
[&](CFG::BasicBlock::Terminated const&)
|
||||
{
|
||||
yulAssert(!_block.operations.empty());
|
||||
if (CFG::BuiltinCall const* builtinCall = get_if<CFG::BuiltinCall>(&_block.operations.back().operation))
|
||||
if (CFG::BuiltinCall const* builtinCall = std::get_if<CFG::BuiltinCall>(&_block.operations.back().operation))
|
||||
yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminatesOrReverts(), "");
|
||||
else if (CFG::FunctionCall const* functionCall = get_if<CFG::FunctionCall>(&_block.operations.back().operation))
|
||||
else if (CFG::FunctionCall const* functionCall = std::get_if<CFG::FunctionCall>(&_block.operations.back().operation))
|
||||
yulAssert(!functionCall->canContinue);
|
||||
else
|
||||
yulAssert(false);
|
||||
|
@ -46,7 +46,6 @@
|
||||
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace std;
|
||||
|
||||
StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
||||
{
|
||||
@ -59,9 +58,9 @@ StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
||||
return stackLayout;
|
||||
}
|
||||
|
||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
|
||||
std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
|
||||
{
|
||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
||||
std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
||||
stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{});
|
||||
for (auto const& function: _cfg.functions)
|
||||
if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty())
|
||||
@ -69,7 +68,7 @@ map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator:
|
||||
return stackTooDeepErrors;
|
||||
}
|
||||
|
||||
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName)
|
||||
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName)
|
||||
{
|
||||
StackLayout stackLayout;
|
||||
CFG::FunctionInfo const* functionInfo = nullptr;
|
||||
@ -98,14 +97,14 @@ StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout, CFG::FunctionIn
|
||||
namespace
|
||||
{
|
||||
/// @returns all stack too deep errors that would occur when shuffling @a _source to @a _target.
|
||||
vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target)
|
||||
std::vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target)
|
||||
{
|
||||
Stack currentStack = _source;
|
||||
vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors;
|
||||
std::vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors;
|
||||
auto getVariableChoices = [](auto&& _range) {
|
||||
vector<YulString> result;
|
||||
std::vector<YulString> result;
|
||||
for (auto const& slot: _range)
|
||||
if (auto const* variableSlot = get_if<VariableSlot>(&slot))
|
||||
if (auto const* variableSlot = std::get_if<VariableSlot>(&slot))
|
||||
if (!util::contains(result, variableSlot->variable.get().name))
|
||||
result.push_back(variableSlot->variable.get().name);
|
||||
return result;
|
||||
@ -160,7 +159,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
|
||||
auto layout = ranges::views::iota(0u, preOperationLayoutSize) |
|
||||
ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) |
|
||||
ranges::to<vector<variant<PreviousSlot, StackSlot>>>;
|
||||
ranges::to<std::vector<std::variant<PreviousSlot, StackSlot>>>;
|
||||
layout += _operationOutput;
|
||||
|
||||
// Shortcut for trivial case.
|
||||
@ -171,23 +170,23 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
// that are aware of PreviousSlot's.
|
||||
struct ShuffleOperations
|
||||
{
|
||||
vector<variant<PreviousSlot, StackSlot>>& layout;
|
||||
std::vector<std::variant<PreviousSlot, StackSlot>>& layout;
|
||||
Stack const& post;
|
||||
std::set<StackSlot> outputs;
|
||||
Multiplicity multiplicity;
|
||||
Callable generateSlotOnTheFly;
|
||||
ShuffleOperations(
|
||||
vector<variant<PreviousSlot, StackSlot>>& _layout,
|
||||
std::vector<std::variant<PreviousSlot, StackSlot>>& _layout,
|
||||
Stack const& _post,
|
||||
Callable _generateSlotOnTheFly
|
||||
): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly)
|
||||
{
|
||||
for (auto const& layoutSlot: layout)
|
||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
||||
if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot))
|
||||
outputs.insert(*slot);
|
||||
|
||||
for (auto const& layoutSlot: layout)
|
||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
||||
if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot))
|
||||
--multiplicity[*slot];
|
||||
for (auto&& slot: post)
|
||||
if (outputs.count(slot) || generateSlotOnTheFly(slot))
|
||||
@ -235,7 +234,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
}
|
||||
void swap(size_t _i)
|
||||
{
|
||||
yulAssert(!holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !holds_alternative<PreviousSlot>(layout.back()), "");
|
||||
yulAssert(!std::holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !std::holds_alternative<PreviousSlot>(layout.back()), "");
|
||||
std::swap(layout.at(layout.size() - _i - 1), layout.back());
|
||||
}
|
||||
size_t sourceSize() { return layout.size(); }
|
||||
@ -250,7 +249,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
|
||||
// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
|
||||
// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
|
||||
vector<optional<StackSlot>> idealLayout(_post.size(), nullopt);
|
||||
std::vector<std::optional<StackSlot>> idealLayout(_post.size(), std::nullopt);
|
||||
for (auto&& [slot, idealPosition]: ranges::zip_view(_post, layout))
|
||||
if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition))
|
||||
idealLayout.at(previousSlot->slot) = slot;
|
||||
@ -261,7 +260,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
|
||||
yulAssert(idealLayout.size() == preOperationLayoutSize, "");
|
||||
|
||||
return idealLayout | ranges::views::transform([](optional<StackSlot> s) {
|
||||
return idealLayout | ranges::views::transform([](std::optional<StackSlot> s) {
|
||||
yulAssert(s, "");
|
||||
return *s;
|
||||
}) | ranges::to<Stack>;
|
||||
@ -271,7 +270,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
||||
Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression)
|
||||
{
|
||||
// Enable aggressive stack compression for recursive calls.
|
||||
if (auto const* functionCall = get_if<CFG::FunctionCall>(&_operation.operation))
|
||||
if (auto const* functionCall = std::get_if<CFG::FunctionCall>(&_operation.operation))
|
||||
if (functionCall->recursive)
|
||||
_aggressiveStackCompression = true;
|
||||
|
||||
@ -285,9 +284,9 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG
|
||||
Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly);
|
||||
|
||||
// Make sure the resulting previous slots do not overlap with any assignmed variables.
|
||||
if (auto const* assignment = get_if<CFG::Assignment>(&_operation.operation))
|
||||
if (auto const* assignment = std::get_if<CFG::Assignment>(&_operation.operation))
|
||||
for (auto& stackSlot: stack)
|
||||
if (auto const* varSlot = get_if<VariableSlot>(&stackSlot))
|
||||
if (auto const* varSlot = std::get_if<VariableSlot>(&stackSlot))
|
||||
yulAssert(!util::contains(assignment->variables, *varSlot), "");
|
||||
|
||||
// Since stack+_operation.output can be easily shuffled to _exitLayout, the desired layout before the operation
|
||||
@ -335,11 +334,11 @@ Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::Ba
|
||||
|
||||
void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG::FunctionInfo const* _functionInfo)
|
||||
{
|
||||
list<CFG::BasicBlock const*> toVisit{&_entry};
|
||||
set<CFG::BasicBlock const*> visited;
|
||||
std::list<CFG::BasicBlock const*> toVisit{&_entry};
|
||||
std::set<CFG::BasicBlock const*> visited;
|
||||
|
||||
// TODO: check whether visiting only a subset of these in the outer iteration below is enough.
|
||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry);
|
||||
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry);
|
||||
|
||||
while (!toVisit.empty())
|
||||
{
|
||||
@ -407,10 +406,10 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG:
|
||||
fillInJunk(_entry, _functionInfo);
|
||||
}
|
||||
|
||||
optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||
std::optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||
CFG::BasicBlock const& _block,
|
||||
set<CFG::BasicBlock const*> const& _visited,
|
||||
list<CFG::BasicBlock const*>& _toVisit
|
||||
std::set<CFG::BasicBlock const*> const& _visited,
|
||||
std::list<CFG::BasicBlock const*>& _toVisit
|
||||
) const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
@ -434,7 +433,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||
return m_layout.blockInfos.at(_jump.target).entryLayout;
|
||||
// Otherwise stage the jump target for visit and defer the current block.
|
||||
_toVisit.emplace_front(_jump.target);
|
||||
return nullopt;
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack>
|
||||
{
|
||||
@ -456,7 +455,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||
_toVisit.emplace_front(_conditionalJump.zero);
|
||||
if (!nonZeroVisited)
|
||||
_toVisit.emplace_front(_conditionalJump.nonZero);
|
||||
return nullopt;
|
||||
return std::nullopt;
|
||||
},
|
||||
[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack>
|
||||
{
|
||||
@ -476,9 +475,9 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||
}, _block.exit);
|
||||
}
|
||||
|
||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const
|
||||
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const
|
||||
{
|
||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
||||
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
||||
util::BreadthFirstSearch<CFG::BasicBlock const*>{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](CFG::BasicBlock::MainExit const&) {},
|
||||
@ -576,7 +575,7 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta
|
||||
if (!util::contains(candidate, slot))
|
||||
candidate.emplace_back(slot);
|
||||
cxx20::erase_if(candidate, [](StackSlot const& slot) {
|
||||
return holds_alternative<LiteralSlot>(slot) || holds_alternative<FunctionCallReturnLabelSlot>(slot);
|
||||
return std::holds_alternative<LiteralSlot>(slot) || std::holds_alternative<FunctionCallReturnLabelSlot>(slot);
|
||||
});
|
||||
|
||||
auto evaluate = [&](Stack const& _candidate) -> size_t {
|
||||
@ -633,9 +632,9 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta
|
||||
return commonPrefix + bestCandidate;
|
||||
}
|
||||
|
||||
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const
|
||||
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const
|
||||
{
|
||||
vector<StackTooDeep> stackTooDeepErrors;
|
||||
std::vector<StackTooDeep> stackTooDeepErrors;
|
||||
util::BreadthFirstSearch<CFG::BasicBlock const*> breadthFirstSearch{{&_entry}};
|
||||
breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
||||
Stack currentStack = m_layout.blockInfos.at(_block).entryLayout;
|
||||
@ -683,7 +682,7 @@ vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooD
|
||||
|
||||
Stack StackLayoutGenerator::compressStack(Stack _stack)
|
||||
{
|
||||
optional<size_t> firstDupOffset;
|
||||
std::optional<size_t> firstDupOffset;
|
||||
do
|
||||
{
|
||||
if (firstDupOffset)
|
||||
@ -768,8 +767,8 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
|
||||
{
|
||||
// This has to be a previously unassigned return variable.
|
||||
// We at least sanity-check that it is among the return variables at all.
|
||||
yulAssert(m_currentFunctionInfo && holds_alternative<VariableSlot>(_slot));
|
||||
yulAssert(util::contains(m_currentFunctionInfo->returnVariables, get<VariableSlot>(_slot)));
|
||||
yulAssert(m_currentFunctionInfo && std::holds_alternative<VariableSlot>(_slot));
|
||||
yulAssert(util::contains(m_currentFunctionInfo->returnVariables, std::get<VariableSlot>(_slot)));
|
||||
// Strictly speaking the cost of the PUSH0 depends on the targeted EVM version, but the difference
|
||||
// will not matter here.
|
||||
opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(0), langutil::EVMVersion());;
|
||||
|
@ -34,6 +34,7 @@ NAMESPACE_STD_FREE_FILES=(
|
||||
libsolidity/lsp/*
|
||||
libsolidity/parsing/*
|
||||
libsolutil/*
|
||||
libyul/backends/evm/*
|
||||
solc/*
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user