mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5334 from ethereum/stringPerformance
[Yul] String performance
This commit is contained in:
commit
deed8e21f6
@ -271,16 +271,16 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
ErrorReporter errorsIgnored(errors);
|
ErrorReporter errorsIgnored(errors);
|
||||||
yul::ExternalIdentifierAccess::Resolver resolver =
|
yul::ExternalIdentifierAccess::Resolver resolver =
|
||||||
[&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
|
[&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
|
||||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name);
|
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
|
||||||
bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot");
|
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
|
||||||
bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset");
|
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
|
||||||
if (isSlot || isOffset)
|
if (isSlot || isOffset)
|
||||||
{
|
{
|
||||||
// special mode to access storage variables
|
// special mode to access storage variables
|
||||||
if (!declarations.empty())
|
if (!declarations.empty())
|
||||||
// the special identifier exists itself, we should not allow that.
|
// the special identifier exists itself, we should not allow that.
|
||||||
return size_t(-1);
|
return size_t(-1);
|
||||||
string realName = _identifier.name.substr(0, _identifier.name.size() - (
|
string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - (
|
||||||
isSlot ?
|
isSlot ?
|
||||||
string("_slot").size() :
|
string("_slot").size() :
|
||||||
string("_offset").size()
|
string("_offset").size()
|
||||||
|
@ -459,7 +459,7 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node)
|
|||||||
if (it.first)
|
if (it.first)
|
||||||
{
|
{
|
||||||
Json::Value tuple(Json::objectValue);
|
Json::Value tuple(Json::objectValue);
|
||||||
tuple[it.first->name] = inlineAssemblyIdentifierToJson(it);
|
tuple[it.first->name.str()] = inlineAssemblyIdentifierToJson(it);
|
||||||
externalReferences.append(tuple);
|
externalReferences.append(tuple);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <libsolidity/inlineasm/AsmCodeGen.h>
|
#include <libsolidity/inlineasm/AsmCodeGen.h>
|
||||||
#include <libsolidity/inlineasm/AsmAnalysis.h>
|
#include <libsolidity/inlineasm/AsmAnalysis.h>
|
||||||
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
|
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
@ -326,7 +327,7 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
bool
|
bool
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
|
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||||
return it == _localVariables.end() ? size_t(-1) : 1;
|
return it == _localVariables.end() ? size_t(-1) : 1;
|
||||||
};
|
};
|
||||||
identifierAccess.generateCode = [&](
|
identifierAccess.generateCode = [&](
|
||||||
@ -335,7 +336,7 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
yul::AbstractAssembly& _assembly
|
yul::AbstractAssembly& _assembly
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
|
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
||||||
solAssert(it != _localVariables.end(), "");
|
solAssert(it != _localVariables.end(), "");
|
||||||
int stackDepth = _localVariables.end() - it;
|
int stackDepth = _localVariables.end() - it;
|
||||||
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
|
||||||
|
@ -79,17 +79,17 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
|
|||||||
|
|
||||||
bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
|
bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
|
||||||
{
|
{
|
||||||
expectValidType(_literal.type, _literal.location);
|
expectValidType(_literal.type.str(), _literal.location);
|
||||||
++m_stackHeight;
|
++m_stackHeight;
|
||||||
if (_literal.kind == assembly::LiteralKind::String && _literal.value.size() > 32)
|
if (_literal.kind == assembly::LiteralKind::String && _literal.value.str().size() > 32)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_literal.location,
|
_literal.location,
|
||||||
"String literal too long (" + to_string(_literal.value.size()) + " > 32)"
|
"String literal too long (" + to_string(_literal.value.str().size()) + " > 32)"
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value) > u256(-1))
|
else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value.str()) > u256(-1))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_literal.location,
|
_literal.location,
|
||||||
@ -100,7 +100,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
|
|||||||
else if (_literal.kind == assembly::LiteralKind::Boolean)
|
else if (_literal.kind == assembly::LiteralKind::Boolean)
|
||||||
{
|
{
|
||||||
solAssert(m_flavour == AsmFlavour::Yul, "");
|
solAssert(m_flavour == AsmFlavour::Yul, "");
|
||||||
solAssert(_literal.value == "true" || _literal.value == "false", "");
|
solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, "");
|
||||||
}
|
}
|
||||||
m_info.stackHeightInfo[&_literal] = m_stackHeight;
|
m_info.stackHeightInfo[&_literal] = m_stackHeight;
|
||||||
return true;
|
return true;
|
||||||
@ -118,7 +118,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
|
|||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_identifier.location,
|
_identifier.location,
|
||||||
"Variable " + _identifier.name + " used before it was declared."
|
"Variable " + _identifier.name.str() + " used before it was declared."
|
||||||
);
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
|
|||||||
{
|
{
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_identifier.location,
|
_identifier.location,
|
||||||
"Function " + _identifier.name + " used without being called."
|
"Function " + _identifier.name.str() + " used without being called."
|
||||||
);
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
|||||||
|
|
||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
expectValidType(variable.type, variable.location);
|
expectValidType(variable.type.str(), variable.location);
|
||||||
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
||||||
}
|
}
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
@ -268,7 +268,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
|
|||||||
Scope& varScope = scope(virtualBlock);
|
Scope& varScope = scope(virtualBlock);
|
||||||
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
||||||
{
|
{
|
||||||
expectValidType(var.type, var.location);
|
expectValidType(var.type.str(), var.location);
|
||||||
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
|
|||||||
if (!expectExpression(*_switch.expression))
|
if (!expectExpression(*_switch.expression))
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
set<tuple<LiteralKind, string>> cases;
|
set<tuple<LiteralKind, YulString>> cases;
|
||||||
for (auto const& _case: _switch.cases)
|
for (auto const& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
if (_case.value)
|
if (_case.value)
|
||||||
@ -503,7 +503,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
|
|||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_variable.location,
|
_variable.location,
|
||||||
"Variable " + _variable.name + " used before it was declared."
|
"Variable " + _variable.name.str() + " used before it was declared."
|
||||||
);
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,13 @@
|
|||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
#include <libevmasm/SourceLocation.h>
|
#include <libevmasm/SourceLocation.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -36,20 +42,21 @@ namespace solidity
|
|||||||
namespace assembly
|
namespace assembly
|
||||||
{
|
{
|
||||||
|
|
||||||
using Type = std::string;
|
using YulString = dev::yul::YulString;
|
||||||
|
using Type = YulString;
|
||||||
|
|
||||||
struct TypedName { SourceLocation location; std::string name; Type type; };
|
struct TypedName { SourceLocation location; YulString name; Type type; };
|
||||||
using TypedNameList = std::vector<TypedName>;
|
using TypedNameList = std::vector<TypedName>;
|
||||||
|
|
||||||
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
||||||
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
||||||
/// Literal number or string (up to 32 bytes)
|
/// Literal number or string (up to 32 bytes)
|
||||||
enum class LiteralKind { Number, Boolean, String };
|
enum class LiteralKind { Number, Boolean, String };
|
||||||
struct Literal { SourceLocation location; LiteralKind kind; std::string value; Type type; };
|
struct Literal { SourceLocation location; LiteralKind kind; YulString value; Type type; };
|
||||||
/// External / internal identifier or label reference
|
/// External / internal identifier or label reference
|
||||||
struct Identifier { SourceLocation location; std::string name; };
|
struct Identifier { SourceLocation location; YulString name; };
|
||||||
/// Jump label ("name:")
|
/// Jump label ("name:")
|
||||||
struct Label { SourceLocation location; std::string name; };
|
struct Label { SourceLocation location; YulString name; };
|
||||||
/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
|
/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
|
||||||
struct StackAssignment { SourceLocation location; Identifier variableName; };
|
struct StackAssignment { SourceLocation location; Identifier variableName; };
|
||||||
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
|
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
|
||||||
@ -69,7 +76,7 @@ struct VariableDeclaration { SourceLocation location; TypedNameList variables; s
|
|||||||
/// Block that creates a scope (frees declared stack variables)
|
/// Block that creates a scope (frees declared stack variables)
|
||||||
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
||||||
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
||||||
struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
|
struct FunctionDefinition { SourceLocation location; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
|
||||||
/// Conditional execution without "else" part.
|
/// Conditional execution without "else" part.
|
||||||
struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
|
struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
|
||||||
/// Switch case or default case
|
/// Switch case or default case
|
||||||
|
@ -112,8 +112,8 @@ assembly::Statement Parser::parseStatement()
|
|||||||
advance();
|
advance();
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
assignment.variableName.location = location();
|
assignment.variableName.location = location();
|
||||||
assignment.variableName.name = currentLiteral();
|
assignment.variableName.name = YulString(currentLiteral());
|
||||||
if (instructions().count(assignment.variableName.name))
|
if (instructions().count(assignment.variableName.name.str()))
|
||||||
fatalParserError("Identifier expected, got instruction name.");
|
fatalParserError("Identifier expected, got instruction name.");
|
||||||
assignment.location.end = endPosition();
|
assignment.location.end = endPosition();
|
||||||
expectToken(Token::Identifier);
|
expectToken(Token::Identifier);
|
||||||
@ -173,7 +173,7 @@ assembly::Statement Parser::parseStatement()
|
|||||||
if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
|
if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
|
||||||
{
|
{
|
||||||
assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location);
|
assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location);
|
||||||
if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name))
|
if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str()))
|
||||||
fatalParserError("Cannot use instruction names for identifier names.");
|
fatalParserError("Cannot use instruction names for identifier names.");
|
||||||
advance();
|
advance();
|
||||||
assignment.variableNames.emplace_back(identifier);
|
assignment.variableNames.emplace_back(identifier);
|
||||||
@ -363,7 +363,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
|
|||||||
ret = Instruction{location(), instr};
|
ret = Instruction{location(), instr};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = Identifier{location(), literal};
|
ret = Identifier{location(), YulString{literal}};
|
||||||
advance();
|
advance();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -394,15 +394,15 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
|
|||||||
Literal literal{
|
Literal literal{
|
||||||
location(),
|
location(),
|
||||||
kind,
|
kind,
|
||||||
currentLiteral(),
|
YulString{currentLiteral()},
|
||||||
""
|
{}
|
||||||
};
|
};
|
||||||
advance();
|
advance();
|
||||||
if (m_flavour == AsmFlavour::Yul)
|
if (m_flavour == AsmFlavour::Yul)
|
||||||
{
|
{
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
literal.location.end = endPosition();
|
literal.location.end = endPosition();
|
||||||
literal.type = expectAsmIdentifier();
|
literal.type = YulString{expectAsmIdentifier()};
|
||||||
}
|
}
|
||||||
else if (kind == LiteralKind::Boolean)
|
else if (kind == LiteralKind::Boolean)
|
||||||
fatalParserError("True and false are not valid literals.");
|
fatalParserError("True and false are not valid literals.");
|
||||||
@ -449,7 +449,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
||||||
expectToken(Token::Function);
|
expectToken(Token::Function);
|
||||||
funDef.name = expectAsmIdentifier();
|
funDef.name = YulString{expectAsmIdentifier()};
|
||||||
expectToken(Token::LParen);
|
expectToken(Token::LParen);
|
||||||
while (currentToken() != Token::RParen)
|
while (currentToken() != Token::RParen)
|
||||||
{
|
{
|
||||||
@ -564,12 +564,12 @@ TypedName Parser::parseTypedName()
|
|||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
TypedName typedName = createWithLocation<TypedName>();
|
TypedName typedName = createWithLocation<TypedName>();
|
||||||
typedName.name = expectAsmIdentifier();
|
typedName.name = YulString{expectAsmIdentifier()};
|
||||||
if (m_flavour == AsmFlavour::Yul)
|
if (m_flavour == AsmFlavour::Yul)
|
||||||
{
|
{
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
typedName.location.end = endPosition();
|
typedName.location.end = endPosition();
|
||||||
typedName.type = expectAsmIdentifier();
|
typedName.type = YulString{expectAsmIdentifier()};
|
||||||
}
|
}
|
||||||
return typedName;
|
return typedName;
|
||||||
}
|
}
|
||||||
|
@ -52,17 +52,17 @@ string AsmPrinter::operator()(assembly::Literal const& _literal)
|
|||||||
switch (_literal.kind)
|
switch (_literal.kind)
|
||||||
{
|
{
|
||||||
case LiteralKind::Number:
|
case LiteralKind::Number:
|
||||||
solAssert(isValidDecimal(_literal.value) || isValidHex(_literal.value), "Invalid number literal");
|
solAssert(isValidDecimal(_literal.value.str()) || isValidHex(_literal.value.str()), "Invalid number literal");
|
||||||
return _literal.value + appendTypeName(_literal.type);
|
return _literal.value.str() + appendTypeName(_literal.type);
|
||||||
case LiteralKind::Boolean:
|
case LiteralKind::Boolean:
|
||||||
solAssert(_literal.value == "true" || _literal.value == "false", "Invalid bool literal.");
|
solAssert(_literal.value.str() == "true" || _literal.value.str() == "false", "Invalid bool literal.");
|
||||||
return ((_literal.value == "true") ? "true" : "false") + appendTypeName(_literal.type);
|
return ((_literal.value.str() == "true") ? "true" : "false") + appendTypeName(_literal.type);
|
||||||
case LiteralKind::String:
|
case LiteralKind::String:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
string out;
|
string out;
|
||||||
for (char c: _literal.value)
|
for (char c: _literal.value.str())
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
out += "\\\\";
|
out += "\\\\";
|
||||||
else if (c == '"')
|
else if (c == '"')
|
||||||
@ -93,7 +93,7 @@ string AsmPrinter::operator()(assembly::Literal const& _literal)
|
|||||||
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
|
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
solAssert(!_identifier.name.empty(), "Invalid identifier.");
|
solAssert(!_identifier.name.empty(), "Invalid identifier.");
|
||||||
return _identifier.name;
|
return _identifier.name.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction)
|
string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction)
|
||||||
@ -118,7 +118,7 @@ string AsmPrinter::operator()(assembly::Label const& _label)
|
|||||||
{
|
{
|
||||||
solAssert(!m_yul, "");
|
solAssert(!m_yul, "");
|
||||||
solAssert(!_label.name.empty(), "Invalid label.");
|
solAssert(!_label.name.empty(), "Invalid label.");
|
||||||
return _label.name + ":";
|
return _label.name.str() + ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
|
string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
|
||||||
@ -157,7 +157,7 @@ string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDecl
|
|||||||
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
||||||
{
|
{
|
||||||
solAssert(!_functionDefinition.name.empty(), "Invalid function name.");
|
solAssert(!_functionDefinition.name.empty(), "Invalid function name.");
|
||||||
string out = "function " + _functionDefinition.name + "(";
|
string out = "function " + _functionDefinition.name.str() + "(";
|
||||||
out += boost::algorithm::join(
|
out += boost::algorithm::join(
|
||||||
_functionDefinition.parameters | boost::adaptors::transformed(
|
_functionDefinition.parameters | boost::adaptors::transformed(
|
||||||
[this](TypedName argument) { return formatTypedName(argument); }
|
[this](TypedName argument) { return formatTypedName(argument); }
|
||||||
@ -239,12 +239,12 @@ string AsmPrinter::operator()(Block const& _block)
|
|||||||
string AsmPrinter::formatTypedName(TypedName _variable) const
|
string AsmPrinter::formatTypedName(TypedName _variable) const
|
||||||
{
|
{
|
||||||
solAssert(!_variable.name.empty(), "Invalid variable name.");
|
solAssert(!_variable.name.empty(), "Invalid variable name.");
|
||||||
return _variable.name + appendTypeName(_variable.type);
|
return _variable.name.str() + appendTypeName(_variable.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::appendTypeName(std::string const& _type) const
|
string AsmPrinter::appendTypeName(YulString _type) const
|
||||||
{
|
{
|
||||||
if (m_yul)
|
if (m_yul)
|
||||||
return ":" + _type;
|
return ":" + _type.str();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -56,7 +58,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string formatTypedName(TypedName _variable) const;
|
std::string formatTypedName(TypedName _variable) const;
|
||||||
std::string appendTypeName(std::string const& _type) const;
|
std::string appendTypeName(yul::YulString _type) const;
|
||||||
|
|
||||||
bool m_yul = false;
|
bool m_yul = false;
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@ using namespace std;
|
|||||||
using namespace dev::solidity::assembly;
|
using namespace dev::solidity::assembly;
|
||||||
|
|
||||||
|
|
||||||
bool Scope::registerLabel(string const& _name)
|
bool Scope::registerLabel(yul::YulString _name)
|
||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
@ -32,7 +32,7 @@ bool Scope::registerLabel(string const& _name)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::registerVariable(string const& _name, YulType const& _type)
|
bool Scope::registerVariable(yul::YulString _name, YulType const& _type)
|
||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
@ -42,7 +42,7 @@ bool Scope::registerVariable(string const& _name, YulType const& _type)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
|
bool Scope::registerFunction(yul::YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
|
||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
@ -50,7 +50,7 @@ bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _a
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::Identifier* Scope::lookup(string const& _name)
|
Scope::Identifier* Scope::lookup(yul::YulString _name)
|
||||||
{
|
{
|
||||||
bool crossedFunctionBoundary = false;
|
bool crossedFunctionBoundary = false;
|
||||||
for (Scope* s = this; s; s = s->superScope)
|
for (Scope* s = this; s; s = s->superScope)
|
||||||
@ -70,7 +70,7 @@ Scope::Identifier* Scope::lookup(string const& _name)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scope::exists(string const& _name) const
|
bool Scope::exists(yul::YulString _name) const
|
||||||
{
|
{
|
||||||
if (identifiers.count(_name))
|
if (identifiers.count(_name))
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/Exceptions.h>
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <libdevcore/Visitor.h>
|
#include <libdevcore/Visitor.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
@ -39,7 +41,7 @@ namespace assembly
|
|||||||
|
|
||||||
struct Scope
|
struct Scope
|
||||||
{
|
{
|
||||||
using YulType = std::string;
|
using YulType = yul::YulString;
|
||||||
using LabelID = size_t;
|
using LabelID = size_t;
|
||||||
|
|
||||||
struct Variable { YulType type; };
|
struct Variable { YulType type; };
|
||||||
@ -54,10 +56,10 @@ struct Scope
|
|||||||
using Visitor = GenericVisitor<Variable const, Label const, Function const>;
|
using Visitor = GenericVisitor<Variable const, Label const, Function const>;
|
||||||
using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
|
using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
|
||||||
|
|
||||||
bool registerVariable(std::string const& _name, YulType const& _type);
|
bool registerVariable(yul::YulString _name, YulType const& _type);
|
||||||
bool registerLabel(std::string const& _name);
|
bool registerLabel(yul::YulString _name);
|
||||||
bool registerFunction(
|
bool registerFunction(
|
||||||
std::string const& _name,
|
yul::YulString _name,
|
||||||
std::vector<YulType> const& _arguments,
|
std::vector<YulType> const& _arguments,
|
||||||
std::vector<YulType> const& _returns
|
std::vector<YulType> const& _returns
|
||||||
);
|
);
|
||||||
@ -67,12 +69,12 @@ struct Scope
|
|||||||
/// will any lookups across assembly boundaries.
|
/// will any lookups across assembly boundaries.
|
||||||
/// The pointer will be invalidated if the scope is modified.
|
/// The pointer will be invalidated if the scope is modified.
|
||||||
/// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup
|
/// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup
|
||||||
Identifier* lookup(std::string const& _name);
|
Identifier* lookup(yul::YulString _name);
|
||||||
/// Looks up the identifier in this and super scopes (will not find variables across function
|
/// Looks up the identifier in this and super scopes (will not find variables across function
|
||||||
/// boundaries and generally stops at assembly boundaries) and calls the visitor, returns
|
/// boundaries and generally stops at assembly boundaries) and calls the visitor, returns
|
||||||
/// false if not found.
|
/// false if not found.
|
||||||
template <class V>
|
template <class V>
|
||||||
bool lookup(std::string const& _name, V const& _visitor)
|
bool lookup(yul::YulString _name, V const& _visitor)
|
||||||
{
|
{
|
||||||
if (Identifier* id = lookup(_name))
|
if (Identifier* id = lookup(_name))
|
||||||
{
|
{
|
||||||
@ -84,7 +86,7 @@ struct Scope
|
|||||||
}
|
}
|
||||||
/// @returns true if the name exists in this scope or in super scopes (also searches
|
/// @returns true if the name exists in this scope or in super scopes (also searches
|
||||||
/// across function and assembly boundaries).
|
/// across function and assembly boundaries).
|
||||||
bool exists(std::string const& _name) const;
|
bool exists(yul::YulString _name) const;
|
||||||
|
|
||||||
/// @returns the number of variables directly registered inside the scope.
|
/// @returns the number of variables directly registered inside the scope.
|
||||||
size_t numberOfVariables() const;
|
size_t numberOfVariables() const;
|
||||||
@ -95,7 +97,7 @@ struct Scope
|
|||||||
/// If true, variables from the super scope are not visible here (other identifiers are),
|
/// If true, variables from the super scope are not visible here (other identifiers are),
|
||||||
/// but they are still taken into account to prevent shadowing.
|
/// but they are still taken into account to prevent shadowing.
|
||||||
bool functionScope = false;
|
bool functionScope = false;
|
||||||
std::map<std::string, Identifier> identifiers;
|
std::map<yul::YulString, Identifier> identifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ bool ScopeFiller::operator()(Label const& _item)
|
|||||||
//@TODO secondary location
|
//@TODO secondary location
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_item.location,
|
_item.location,
|
||||||
"Label name " + _item.name + " already taken in this scope."
|
"Label name " + _item.name.str() + " already taken in this scope."
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -77,16 +77,16 @@ bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
vector<Scope::YulType> arguments;
|
vector<Scope::YulType> arguments;
|
||||||
for (auto const& _argument: _funDef.parameters)
|
for (auto const& _argument: _funDef.parameters)
|
||||||
arguments.push_back(_argument.type);
|
arguments.emplace_back(_argument.type.str());
|
||||||
vector<Scope::YulType> returns;
|
vector<Scope::YulType> returns;
|
||||||
for (auto const& _return: _funDef.returnVariables)
|
for (auto const& _return: _funDef.returnVariables)
|
||||||
returns.push_back(_return.type);
|
returns.emplace_back(_return.type.str());
|
||||||
if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
|
if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
|
||||||
{
|
{
|
||||||
//@TODO secondary location
|
//@TODO secondary location
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_funDef.location,
|
_funDef.location,
|
||||||
"Function name " + _funDef.name + " already taken in this scope."
|
"Function name " + _funDef.name.str() + " already taken in this scope."
|
||||||
);
|
);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const&
|
|||||||
//@TODO secondary location
|
//@TODO secondary location
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_location,
|
_location,
|
||||||
"Variable name " + _name.name + " already taken in this scope."
|
"Variable name " + _name.name.str() + " already taken in this scope."
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ using ExpressionStatement = solidity::assembly::ExpressionStatement;
|
|||||||
using Block = solidity::assembly::Block;
|
using Block = solidity::assembly::Block;
|
||||||
|
|
||||||
using TypedName = solidity::assembly::TypedName;
|
using TypedName = solidity::assembly::TypedName;
|
||||||
|
class YulString;
|
||||||
|
|
||||||
using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
|
using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
|
||||||
using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
|
||||||
|
96
libyul/YulString.h
Normal file
96
libyul/YulString.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* String abstraction that avoids copies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace yul
|
||||||
|
{
|
||||||
|
|
||||||
|
class YulStringRepository: boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
YulStringRepository(): m_strings{std::make_shared<std::string>()}
|
||||||
|
{
|
||||||
|
m_ids[std::string{}] = 0;
|
||||||
|
}
|
||||||
|
static YulStringRepository& instance()
|
||||||
|
{
|
||||||
|
static YulStringRepository inst;
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
size_t stringToId(std::string const& _string)
|
||||||
|
{
|
||||||
|
if (_string.empty())
|
||||||
|
return 0;
|
||||||
|
size_t& id = m_ids[_string];
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
m_strings.emplace_back(std::make_shared<std::string>(_string));
|
||||||
|
id = m_strings.size() - 1;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
std::string const& idToString(size_t _id) const
|
||||||
|
{
|
||||||
|
return *m_strings.at(_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<std::string>> m_strings;
|
||||||
|
std::map<std::string, size_t> m_ids;
|
||||||
|
};
|
||||||
|
|
||||||
|
class YulString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
YulString() = default;
|
||||||
|
explicit YulString(std::string const& _s): m_id(YulStringRepository::instance().stringToId(_s)) {}
|
||||||
|
YulString(YulString const&) = default;
|
||||||
|
YulString(YulString&&) = default;
|
||||||
|
YulString& operator=(YulString const&) = default;
|
||||||
|
YulString& operator=(YulString&&) = default;
|
||||||
|
|
||||||
|
/// This is not consistent with the string <-operator!
|
||||||
|
bool operator<(YulString const& _other) const { return m_id < _other.m_id; }
|
||||||
|
bool operator==(YulString const& _other) const { return m_id == _other.m_id; }
|
||||||
|
bool operator!=(YulString const& _other) const { return m_id != _other.m_id; }
|
||||||
|
|
||||||
|
bool empty() const { return m_id == 0; }
|
||||||
|
std::string const& str() const
|
||||||
|
{
|
||||||
|
return YulStringRepository::instance().idToString(m_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// ID of the string. Assumes that the empty string has ID zero.
|
||||||
|
size_t m_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -201,18 +201,18 @@ void CodeTransform::operator()(assembly::Literal const& _literal)
|
|||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(_literal.location);
|
m_assembly.setSourceLocation(_literal.location);
|
||||||
if (_literal.kind == assembly::LiteralKind::Number)
|
if (_literal.kind == assembly::LiteralKind::Number)
|
||||||
m_assembly.appendConstant(u256(_literal.value));
|
m_assembly.appendConstant(u256(_literal.value.str()));
|
||||||
else if (_literal.kind == assembly::LiteralKind::Boolean)
|
else if (_literal.kind == assembly::LiteralKind::Boolean)
|
||||||
{
|
{
|
||||||
if (_literal.value == "true")
|
if (_literal.value.str() == "true")
|
||||||
m_assembly.appendConstant(u256(1));
|
m_assembly.appendConstant(u256(1));
|
||||||
else
|
else
|
||||||
m_assembly.appendConstant(u256(0));
|
m_assembly.appendConstant(u256(0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(_literal.value.size() <= 32, "");
|
solAssert(_literal.value.str().size() <= 32, "");
|
||||||
m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft)));
|
m_assembly.appendConstant(u256(h256(_literal.value.str(), h256::FromBinary, h256::AlignLeft)));
|
||||||
}
|
}
|
||||||
checkStackHeight(&_literal);
|
checkStackHeight(&_literal);
|
||||||
}
|
}
|
||||||
@ -454,13 +454,13 @@ AbstractAssembly::LabelID CodeTransform::labelID(Scope::Label const& _label)
|
|||||||
return m_context->labelIDs[&_label];
|
return m_context->labelIDs[&_label];
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Scope::Function const& _function)
|
AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function)
|
||||||
{
|
{
|
||||||
if (!m_context->functionEntryIDs.count(&_function))
|
if (!m_context->functionEntryIDs.count(&_function))
|
||||||
{
|
{
|
||||||
AbstractAssembly::LabelID id =
|
AbstractAssembly::LabelID id =
|
||||||
m_useNamedLabelsForFunctions ?
|
m_useNamedLabelsForFunctions ?
|
||||||
m_assembly.namedLabel(_name) :
|
m_assembly.namedLabel(_name.str()) :
|
||||||
m_assembly.newLabelId();
|
m_assembly.newLabelId();
|
||||||
m_context->functionEntryIDs[&_function] = id;
|
m_context->functionEntryIDs[&_function] = id;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ private:
|
|||||||
/// @returns the label ID corresponding to the given label, allocating a new one if
|
/// @returns the label ID corresponding to the given label, allocating a new one if
|
||||||
/// necessary.
|
/// necessary.
|
||||||
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
|
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
|
||||||
AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function);
|
AbstractAssembly::LabelID functionEntryID(YulString _name, solidity::assembly::Scope::Function const& _function);
|
||||||
/// Generates code for an expression that is supposed to return a single value.
|
/// Generates code for an expression that is supposed to return a single value.
|
||||||
void visitExpression(Expression const& _expression);
|
void visitExpression(Expression const& _expression);
|
||||||
|
|
||||||
|
@ -111,14 +111,14 @@ Statement ASTCopier::operator()(Switch const& _switch)
|
|||||||
|
|
||||||
Statement ASTCopier::operator()(FunctionDefinition const& _function)
|
Statement ASTCopier::operator()(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
string translatedName = translateIdentifier(_function.name);
|
YulString translatedName = translateIdentifier(_function.name);
|
||||||
|
|
||||||
enterFunction(_function);
|
enterFunction(_function);
|
||||||
ScopeGuard g([&]() { this->leaveFunction(_function); });
|
ScopeGuard g([&]() { this->leaveFunction(_function); });
|
||||||
|
|
||||||
return FunctionDefinition{
|
return FunctionDefinition{
|
||||||
_function.location,
|
_function.location,
|
||||||
move(translatedName),
|
translatedName,
|
||||||
translateVector(_function.parameters),
|
translateVector(_function.parameters),
|
||||||
translateVector(_function.returnVariables),
|
translateVector(_function.returnVariables),
|
||||||
translate(_function.body)
|
translate(_function.body)
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <libyul/ASTDataForward.h>
|
#include <libyul/ASTDataForward.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
@ -107,7 +109,7 @@ protected:
|
|||||||
virtual void leaveScope(Block const&) { }
|
virtual void leaveScope(Block const&) { }
|
||||||
virtual void enterFunction(FunctionDefinition const&) { }
|
virtual void enterFunction(FunctionDefinition const&) { }
|
||||||
virtual void leaveFunction(FunctionDefinition const&) { }
|
virtual void leaveFunction(FunctionDefinition const&) { }
|
||||||
virtual std::string translateIdentifier(std::string const& _name) { return _name; }
|
virtual YulString translateIdentifier(YulString _name) { return _name; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libyul/ASTDataForward.h>
|
#include <libyul/ASTDataForward.h>
|
||||||
|
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
@ -43,13 +43,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
|||||||
if (_e.type() == typeid(Identifier))
|
if (_e.type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
Identifier& identifier = boost::get<Identifier>(_e);
|
Identifier& identifier = boost::get<Identifier>(_e);
|
||||||
string const& name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
assertThrow(m_value.at(name), OptimizerException, "");
|
assertThrow(m_value.at(name), OptimizerException, "");
|
||||||
if (m_value.at(name)->type() == typeid(Identifier))
|
if (m_value.at(name)->type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
string const& value = boost::get<Identifier>(*m_value.at(name)).name;
|
YulString value = boost::get<Identifier>(*m_value.at(name)).name;
|
||||||
assertThrow(inScope(value), OptimizerException, "");
|
assertThrow(inScope(value), OptimizerException, "");
|
||||||
_e = Identifier{locationOf(_e), value};
|
_e = Identifier{locationOf(_e), value};
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,9 @@ using namespace dev::yul;
|
|||||||
|
|
||||||
void DataFlowAnalyzer::operator()(Assignment& _assignment)
|
void DataFlowAnalyzer::operator()(Assignment& _assignment)
|
||||||
{
|
{
|
||||||
set<string> names;
|
set<YulString> names;
|
||||||
for (auto const& var: _assignment.variableNames)
|
for (auto const& var: _assignment.variableNames)
|
||||||
names.insert(var.name);
|
names.emplace(var.name);
|
||||||
assertThrow(_assignment.value, OptimizerException, "");
|
assertThrow(_assignment.value, OptimizerException, "");
|
||||||
visit(*_assignment.value);
|
visit(*_assignment.value);
|
||||||
handleAssignment(names, _assignment.value.get());
|
handleAssignment(names, _assignment.value.get());
|
||||||
@ -48,9 +48,9 @@ void DataFlowAnalyzer::operator()(Assignment& _assignment)
|
|||||||
|
|
||||||
void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
|
void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
|
||||||
{
|
{
|
||||||
set<string> names;
|
set<YulString> names;
|
||||||
for (auto const& var: _varDecl.variables)
|
for (auto const& var: _varDecl.variables)
|
||||||
names.insert(var.name);
|
names.emplace(var.name);
|
||||||
m_variableScopes.back().variables += names;
|
m_variableScopes.back().variables += names;
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
visit(*_varDecl.value);
|
visit(*_varDecl.value);
|
||||||
@ -69,7 +69,7 @@ void DataFlowAnalyzer::operator()(If& _if)
|
|||||||
void DataFlowAnalyzer::operator()(Switch& _switch)
|
void DataFlowAnalyzer::operator()(Switch& _switch)
|
||||||
{
|
{
|
||||||
visit(*_switch.expression);
|
visit(*_switch.expression);
|
||||||
set<string> assignedVariables;
|
set<YulString> assignedVariables;
|
||||||
for (auto& _case: _switch.cases)
|
for (auto& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
(*this)(_case.body);
|
(*this)(_case.body);
|
||||||
@ -86,9 +86,9 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun)
|
|||||||
{
|
{
|
||||||
pushScope(true);
|
pushScope(true);
|
||||||
for (auto const& parameter: _fun.parameters)
|
for (auto const& parameter: _fun.parameters)
|
||||||
m_variableScopes.back().variables.insert(parameter.name);
|
m_variableScopes.back().variables.emplace(parameter.name);
|
||||||
for (auto const& var: _fun.returnVariables)
|
for (auto const& var: _fun.returnVariables)
|
||||||
m_variableScopes.back().variables.insert(var.name);
|
m_variableScopes.back().variables.emplace(var.name);
|
||||||
ASTModifier::operator()(_fun);
|
ASTModifier::operator()(_fun);
|
||||||
popScope();
|
popScope();
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ void DataFlowAnalyzer::operator()(Block& _block)
|
|||||||
assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
|
assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expression* _value)
|
void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value)
|
||||||
{
|
{
|
||||||
clearValues(_variables);
|
clearValues(_variables);
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio
|
|||||||
movableChecker.visit(*_value);
|
movableChecker.visit(*_value);
|
||||||
if (_variables.size() == 1)
|
if (_variables.size() == 1)
|
||||||
{
|
{
|
||||||
string const& name = *_variables.begin();
|
YulString name = *_variables.begin();
|
||||||
// Expression has to be movable and cannot contain a reference
|
// Expression has to be movable and cannot contain a reference
|
||||||
// to the variable that will be assigned to.
|
// to the variable that will be assigned to.
|
||||||
if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name))
|
if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name))
|
||||||
@ -143,7 +143,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio
|
|||||||
{
|
{
|
||||||
m_references[name] = referencedVariables;
|
m_references[name] = referencedVariables;
|
||||||
for (auto const& ref: referencedVariables)
|
for (auto const& ref: referencedVariables)
|
||||||
m_referencedBy[ref].insert(name);
|
m_referencedBy[ref].emplace(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ void DataFlowAnalyzer::popScope()
|
|||||||
m_variableScopes.pop_back();
|
m_variableScopes.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFlowAnalyzer::clearValues(set<string> _variables)
|
void DataFlowAnalyzer::clearValues(set<YulString> _variables)
|
||||||
{
|
{
|
||||||
// All variables that reference variables to be cleared also have to be
|
// All variables that reference variables to be cleared also have to be
|
||||||
// cleared, but not recursively, since only the value of the original
|
// cleared, but not recursively, since only the value of the original
|
||||||
@ -176,7 +176,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables)
|
|||||||
// Clear variables that reference variables to be cleared.
|
// Clear variables that reference variables to be cleared.
|
||||||
for (auto const& name: _variables)
|
for (auto const& name: _variables)
|
||||||
for (auto const& ref: m_referencedBy[name])
|
for (auto const& ref: m_referencedBy[name])
|
||||||
_variables.insert(ref);
|
_variables.emplace(ref);
|
||||||
|
|
||||||
// Clear the value and update the reference relation.
|
// Clear the value and update the reference relation.
|
||||||
for (auto const& name: _variables)
|
for (auto const& name: _variables)
|
||||||
@ -189,7 +189,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataFlowAnalyzer::inScope(string const& _variableName) const
|
bool DataFlowAnalyzer::inScope(YulString _variableName) const
|
||||||
{
|
{
|
||||||
for (auto const& scope: m_variableScopes | boost::adaptors::reversed)
|
for (auto const& scope: m_variableScopes | boost::adaptors::reversed)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
|
||||||
#include <string>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Registers the assignment.
|
/// Registers the assignment.
|
||||||
void handleAssignment(std::set<std::string> const& _names, Expression* _value);
|
void handleAssignment(std::set<YulString> const& _names, Expression* _value);
|
||||||
|
|
||||||
/// Creates a new inner scope.
|
/// Creates a new inner scope.
|
||||||
void pushScope(bool _functionScope);
|
void pushScope(bool _functionScope);
|
||||||
@ -64,22 +65,22 @@ protected:
|
|||||||
|
|
||||||
/// Clears information about the values assigned to the given variables,
|
/// Clears information about the values assigned to the given variables,
|
||||||
/// for example at points where control flow is merged.
|
/// for example at points where control flow is merged.
|
||||||
void clearValues(std::set<std::string> _names);
|
void clearValues(std::set<YulString> _names);
|
||||||
|
|
||||||
/// Returns true iff the variable is in scope.
|
/// Returns true iff the variable is in scope.
|
||||||
bool inScope(std::string const& _variableName) const;
|
bool inScope(YulString _variableName) const;
|
||||||
|
|
||||||
/// Current values of variables, always movable.
|
/// Current values of variables, always movable.
|
||||||
std::map<std::string, Expression const*> m_value;
|
std::map<YulString, Expression const*> m_value;
|
||||||
/// m_references[a].contains(b) <=> the current expression assigned to a references b
|
/// m_references[a].contains(b) <=> the current expression assigned to a references b
|
||||||
std::map<std::string, std::set<std::string>> m_references;
|
std::map<YulString, std::set<YulString>> m_references;
|
||||||
/// m_referencedBy[b].contains(a) <=> the current expression assigned to a references b
|
/// m_referencedBy[b].contains(a) <=> the current expression assigned to a references b
|
||||||
std::map<std::string, std::set<std::string>> m_referencedBy;
|
std::map<YulString, std::set<YulString>> m_referencedBy;
|
||||||
|
|
||||||
struct Scope
|
struct Scope
|
||||||
{
|
{
|
||||||
explicit Scope(bool _isFunction): isFunction(_isFunction) {}
|
explicit Scope(bool _isFunction): isFunction(_isFunction) {}
|
||||||
std::set<std::string> variables;
|
std::set<YulString> variables;
|
||||||
bool isFunction;
|
bool isFunction;
|
||||||
};
|
};
|
||||||
/// List of scopes.
|
/// List of scopes.
|
||||||
|
@ -32,7 +32,7 @@ using namespace dev::solidity;
|
|||||||
|
|
||||||
using Scope = dev::solidity::assembly::Scope;
|
using Scope = dev::solidity::assembly::Scope;
|
||||||
|
|
||||||
string Disambiguator::translateIdentifier(string const& _originalName)
|
YulString Disambiguator::translateIdentifier(YulString _originalName)
|
||||||
{
|
{
|
||||||
if ((m_externallyUsedIdentifiers.count(_originalName)))
|
if ((m_externallyUsedIdentifiers.count(_originalName)))
|
||||||
return _originalName;
|
return _originalName;
|
||||||
|
@ -45,7 +45,7 @@ class Disambiguator: public ASTCopier
|
|||||||
public:
|
public:
|
||||||
explicit Disambiguator(
|
explicit Disambiguator(
|
||||||
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
||||||
std::set<std::string> const& _externallyUsedIdentifiers = {}
|
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
||||||
):
|
):
|
||||||
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers)
|
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers)
|
||||||
{
|
{
|
||||||
@ -56,16 +56,16 @@ protected:
|
|||||||
virtual void leaveScope(Block const& _block) override;
|
virtual void leaveScope(Block const& _block) override;
|
||||||
virtual void enterFunction(FunctionDefinition const& _function) override;
|
virtual void enterFunction(FunctionDefinition const& _function) override;
|
||||||
virtual void leaveFunction(FunctionDefinition const& _function) override;
|
virtual void leaveFunction(FunctionDefinition const& _function) override;
|
||||||
virtual std::string translateIdentifier(std::string const& _name) override;
|
virtual YulString translateIdentifier(YulString _name) override;
|
||||||
|
|
||||||
void enterScopeInternal(solidity::assembly::Scope& _scope);
|
void enterScopeInternal(solidity::assembly::Scope& _scope);
|
||||||
void leaveScopeInternal(solidity::assembly::Scope& _scope);
|
void leaveScopeInternal(solidity::assembly::Scope& _scope);
|
||||||
|
|
||||||
solidity::assembly::AsmAnalysisInfo const& m_info;
|
solidity::assembly::AsmAnalysisInfo const& m_info;
|
||||||
std::set<std::string> const& m_externallyUsedIdentifiers;
|
std::set<YulString> const& m_externallyUsedIdentifiers;
|
||||||
|
|
||||||
std::vector<solidity::assembly::Scope*> m_scopes;
|
std::vector<solidity::assembly::Scope*> m_scopes;
|
||||||
std::map<void const*, std::string> m_translations;
|
std::map<void const*, YulString> m_translations;
|
||||||
NameDispenser m_nameDispenser;
|
NameDispenser m_nameDispenser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ void ExpressionInliner::visit(Expression& _expression)
|
|||||||
if (m_inlinableFunctions.count(funCall.functionName.name) && movable)
|
if (m_inlinableFunctions.count(funCall.functionName.name) && movable)
|
||||||
{
|
{
|
||||||
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
|
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
|
||||||
map<string, Expression const*> substitutions;
|
map<YulString, Expression const*> substitutions;
|
||||||
for (size_t i = 0; i < fun.parameters.size(); ++i)
|
for (size_t i = 0; i < fun.parameters.size(); ++i)
|
||||||
substitutions[fun.parameters[i].name] = &funCall.arguments[i];
|
substitutions[fun.parameters[i].name] = &funCall.arguments[i];
|
||||||
_expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value);
|
_expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value);
|
||||||
|
@ -59,10 +59,10 @@ public:
|
|||||||
virtual void visit(Expression& _expression) override;
|
virtual void visit(Expression& _expression) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, FunctionDefinition const*> m_inlinableFunctions;
|
std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
|
||||||
std::map<std::string, std::string> m_varReplacements;
|
std::map<YulString, YulString> m_varReplacements;
|
||||||
/// Set of functions we are currently visiting inside.
|
/// Set of functions we are currently visiting inside.
|
||||||
std::set<std::string> m_currentFunctions;
|
std::set<YulString> m_currentFunctions;
|
||||||
|
|
||||||
Block& m_block;
|
Block& m_block;
|
||||||
};
|
};
|
||||||
|
@ -93,9 +93,9 @@ private:
|
|||||||
bool isLatestStatementVarDeclJoinable(Identifier const& _identifier);
|
bool isLatestStatementVarDeclJoinable(Identifier const& _identifier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Block* m_currentBlock = nullptr; ///< Pointer to currently block holding the visiting statement.
|
Block* m_currentBlock = nullptr; ///< Pointer to current block holding the statement being visited.
|
||||||
size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement.
|
size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement.
|
||||||
std::map<std::string, size_t> m_references; ///< Holds reference counts to all variable declarations in current block.
|
std::map<YulString, size_t> m_references; ///< Holds reference counts to all variable declarations in current block.
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,11 +44,11 @@ public:
|
|||||||
|
|
||||||
static void run(Block& _ast);
|
static void run(Block& _ast);
|
||||||
private:
|
private:
|
||||||
explicit ExpressionSimplifier(std::map<std::string, Expression const*> _ssaValues):
|
explicit ExpressionSimplifier(std::map<YulString, Expression const*> _ssaValues):
|
||||||
m_ssaValues(std::move(_ssaValues))
|
m_ssaValues(std::move(_ssaValues))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::map<std::string, Expression const*> m_ssaValues;
|
std::map<YulString, Expression const*> m_ssaValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,10 @@ void ExpressionSplitter::outlineExpression(Expression& _expr)
|
|||||||
visit(_expr);
|
visit(_expr);
|
||||||
|
|
||||||
SourceLocation location = locationOf(_expr);
|
SourceLocation location = locationOf(_expr);
|
||||||
string var = m_nameDispenser.newName("");
|
YulString var = m_nameDispenser.newName({});
|
||||||
m_statementsToPrefix.emplace_back(VariableDeclaration{
|
m_statementsToPrefix.emplace_back(VariableDeclaration{
|
||||||
location,
|
location,
|
||||||
{{TypedName{location, var, ""}}},
|
{{TypedName{location, var, {}}}},
|
||||||
make_shared<Expression>(std::move(_expr))
|
make_shared<Expression>(std::move(_expr))
|
||||||
});
|
});
|
||||||
_expr = Identifier{location, var};
|
_expr = Identifier{location, var};
|
||||||
|
@ -48,9 +48,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
|||||||
tracker(m_ast);
|
tracker(m_ast);
|
||||||
for (auto const& ssaValue: tracker.values())
|
for (auto const& ssaValue: tracker.values())
|
||||||
if (ssaValue.second && ssaValue.second->type() == typeid(Literal))
|
if (ssaValue.second && ssaValue.second->type() == typeid(Literal))
|
||||||
m_constants.insert(ssaValue.first);
|
m_constants.emplace(ssaValue.first);
|
||||||
|
|
||||||
map<string, size_t> references = ReferencesCounter::countReferences(m_ast);
|
map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast);
|
||||||
for (auto& statement: m_ast.statements)
|
for (auto& statement: m_ast.statements)
|
||||||
{
|
{
|
||||||
if (statement.type() != typeid(FunctionDefinition))
|
if (statement.type() != typeid(FunctionDefinition))
|
||||||
@ -59,7 +59,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
|||||||
m_functions[fun.name] = &fun;
|
m_functions[fun.name] = &fun;
|
||||||
// Always inline functions that are only called once.
|
// Always inline functions that are only called once.
|
||||||
if (references[fun.name] == 1)
|
if (references[fun.name] == 1)
|
||||||
m_alwaysInline.insert(fun.name);
|
m_alwaysInline.emplace(fun.name);
|
||||||
updateCodeSize(fun);
|
updateCodeSize(fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ void FullInliner::run()
|
|||||||
{
|
{
|
||||||
for (auto& statement: m_ast.statements)
|
for (auto& statement: m_ast.statements)
|
||||||
if (statement.type() == typeid(Block))
|
if (statement.type() == typeid(Block))
|
||||||
handleBlock("", boost::get<Block>(statement));
|
handleBlock({}, boost::get<Block>(statement));
|
||||||
|
|
||||||
// TODO it might be good to determine a visiting order:
|
// TODO it might be good to determine a visiting order:
|
||||||
// first handle functions that are called from many places.
|
// first handle functions that are called from many places.
|
||||||
@ -84,12 +84,12 @@ void FullInliner::updateCodeSize(FunctionDefinition& fun)
|
|||||||
m_functionSizes[fun.name] = CodeSize::codeSize(fun.body);
|
m_functionSizes[fun.name] = CodeSize::codeSize(fun.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullInliner::handleBlock(string const& _currentFunctionName, Block& _block)
|
void FullInliner::handleBlock(YulString _currentFunctionName, Block& _block)
|
||||||
{
|
{
|
||||||
InlineModifier{*this, m_nameDispenser, _currentFunctionName}(_block);
|
InlineModifier{*this, m_nameDispenser, _currentFunctionName}(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FullInliner::shallInline(FunctionCall const& _funCall, string const& _callSite)
|
bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
||||||
{
|
{
|
||||||
// No recursive inlining
|
// No recursive inlining
|
||||||
if (_funCall.functionName.name == _callSite)
|
if (_funCall.functionName.name == _callSite)
|
||||||
@ -148,14 +148,14 @@ boost::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement&
|
|||||||
vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall)
|
vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall)
|
||||||
{
|
{
|
||||||
vector<Statement> newStatements;
|
vector<Statement> newStatements;
|
||||||
map<string, string> variableReplacements;
|
map<YulString, YulString> variableReplacements;
|
||||||
|
|
||||||
FunctionDefinition& function = m_driver.function(_funCall.functionName.name);
|
FunctionDefinition& function = m_driver.function(_funCall.functionName.name);
|
||||||
|
|
||||||
// helper function to create a new variable that is supposed to model
|
// helper function to create a new variable that is supposed to model
|
||||||
// an existing variable.
|
// an existing variable.
|
||||||
auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) {
|
auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) {
|
||||||
string newName = m_nameDispenser.newName(_existingVariable.name, function.name);
|
YulString newName = m_nameDispenser.newName(_existingVariable.name, function.name);
|
||||||
variableReplacements[_existingVariable.name] = newName;
|
variableReplacements[_existingVariable.name] = newName;
|
||||||
VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}};
|
VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}};
|
||||||
if (_value)
|
if (_value)
|
||||||
@ -214,7 +214,7 @@ Statement BodyCopier::operator()(FunctionDefinition const& _funDef)
|
|||||||
return _funDef;
|
return _funDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
string BodyCopier::translateIdentifier(string const& _name)
|
YulString BodyCopier::translateIdentifier(YulString _name)
|
||||||
{
|
{
|
||||||
if (m_variableReplacements.count(_name))
|
if (m_variableReplacements.count(_name))
|
||||||
return m_variableReplacements.at(_name);
|
return m_variableReplacements.at(_name);
|
||||||
|
@ -77,23 +77,23 @@ public:
|
|||||||
|
|
||||||
/// Inlining heuristic.
|
/// Inlining heuristic.
|
||||||
/// @param _callSite the name of the function in which the function call is located.
|
/// @param _callSite the name of the function in which the function call is located.
|
||||||
bool shallInline(FunctionCall const& _funCall, std::string const& _callSite);
|
bool shallInline(FunctionCall const& _funCall, YulString _callSite);
|
||||||
|
|
||||||
FunctionDefinition& function(std::string _name) { return *m_functions.at(_name); }
|
FunctionDefinition& function(YulString _name) { return *m_functions.at(_name); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateCodeSize(FunctionDefinition& fun);
|
void updateCodeSize(FunctionDefinition& fun);
|
||||||
void handleBlock(std::string const& _currentFunctionName, Block& _block);
|
void handleBlock(YulString _currentFunctionName, Block& _block);
|
||||||
|
|
||||||
/// The AST to be modified. The root block itself will not be modified, because
|
/// The AST to be modified. The root block itself will not be modified, because
|
||||||
/// we store pointers to functions.
|
/// we store pointers to functions.
|
||||||
Block& m_ast;
|
Block& m_ast;
|
||||||
std::map<std::string, FunctionDefinition*> m_functions;
|
std::map<YulString, FunctionDefinition*> m_functions;
|
||||||
/// Names of functions to always inline.
|
/// Names of functions to always inline.
|
||||||
std::set<std::string> m_alwaysInline;
|
std::set<YulString> m_alwaysInline;
|
||||||
/// Variables that are constants (used for inlining heuristic)
|
/// Variables that are constants (used for inlining heuristic)
|
||||||
std::set<std::string> m_constants;
|
std::set<YulString> m_constants;
|
||||||
std::map<std::string, size_t> m_functionSizes;
|
std::map<YulString, size_t> m_functionSizes;
|
||||||
NameDispenser& m_nameDispenser;
|
NameDispenser& m_nameDispenser;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ private:
|
|||||||
class InlineModifier: public ASTModifier
|
class InlineModifier: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, std::string _functionName):
|
InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, YulString _functionName):
|
||||||
m_currentFunction(std::move(_functionName)),
|
m_currentFunction(std::move(_functionName)),
|
||||||
m_driver(_driver),
|
m_driver(_driver),
|
||||||
m_nameDispenser(_nameDispenser)
|
m_nameDispenser(_nameDispenser)
|
||||||
@ -116,7 +116,7 @@ private:
|
|||||||
boost::optional<std::vector<Statement>> tryInlineStatement(Statement& _statement);
|
boost::optional<std::vector<Statement>> tryInlineStatement(Statement& _statement);
|
||||||
std::vector<Statement> performInline(Statement& _statement, FunctionCall& _funCall);
|
std::vector<Statement> performInline(Statement& _statement, FunctionCall& _funCall);
|
||||||
|
|
||||||
std::string m_currentFunction;
|
YulString m_currentFunction;
|
||||||
FullInliner& m_driver;
|
FullInliner& m_driver;
|
||||||
NameDispenser& m_nameDispenser;
|
NameDispenser& m_nameDispenser;
|
||||||
};
|
};
|
||||||
@ -131,8 +131,8 @@ class BodyCopier: public ASTCopier
|
|||||||
public:
|
public:
|
||||||
BodyCopier(
|
BodyCopier(
|
||||||
NameDispenser& _nameDispenser,
|
NameDispenser& _nameDispenser,
|
||||||
std::string const& _varNamePrefix,
|
YulString _varNamePrefix,
|
||||||
std::map<std::string, std::string> const& _variableReplacements
|
std::map<YulString, YulString> const& _variableReplacements
|
||||||
):
|
):
|
||||||
m_nameDispenser(_nameDispenser),
|
m_nameDispenser(_nameDispenser),
|
||||||
m_varNamePrefix(_varNamePrefix),
|
m_varNamePrefix(_varNamePrefix),
|
||||||
@ -144,11 +144,11 @@ public:
|
|||||||
virtual Statement operator()(VariableDeclaration const& _varDecl) override;
|
virtual Statement operator()(VariableDeclaration const& _varDecl) override;
|
||||||
virtual Statement operator()(FunctionDefinition const& _funDef) override;
|
virtual Statement operator()(FunctionDefinition const& _funDef) override;
|
||||||
|
|
||||||
virtual std::string translateIdentifier(std::string const& _name) override;
|
virtual YulString translateIdentifier(YulString _name) override;
|
||||||
|
|
||||||
NameDispenser& m_nameDispenser;
|
NameDispenser& m_nameDispenser;
|
||||||
std::string const& m_varNamePrefix;
|
YulString m_varNamePrefix;
|
||||||
std::map<std::string, std::string> m_variableReplacements;
|
std::map<YulString, YulString> m_variableReplacements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
|
|||||||
{
|
{
|
||||||
if (_function.returnVariables.size() == 1 && _function.body.statements.size() == 1)
|
if (_function.returnVariables.size() == 1 && _function.body.statements.size() == 1)
|
||||||
{
|
{
|
||||||
string const& retVariable = _function.returnVariables.front().name;
|
YulString retVariable = _function.returnVariables.front().name;
|
||||||
Statement const& bodyStatement = _function.body.statements.front();
|
Statement const& bodyStatement = _function.body.statements.front();
|
||||||
if (bodyStatement.type() == typeid(Assignment))
|
if (bodyStatement.type() == typeid(Assignment))
|
||||||
{
|
{
|
||||||
@ -57,7 +57,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
|
|||||||
// would not be valid here if we were searching inside a functionally inlinable
|
// would not be valid here if we were searching inside a functionally inlinable
|
||||||
// function body.
|
// function body.
|
||||||
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
|
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
|
||||||
m_disallowedIdentifiers = set<string>{retVariable, _function.name};
|
m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
|
||||||
boost::apply_visitor(*this, *assignment.value);
|
boost::apply_visitor(*this, *assignment.value);
|
||||||
if (!m_foundDisallowedIdentifier)
|
if (!m_foundDisallowedIdentifier)
|
||||||
m_inlinableFunctions[_function.name] = &_function;
|
m_inlinableFunctions[_function.name] = &_function;
|
||||||
|
@ -43,7 +43,7 @@ class InlinableExpressionFunctionFinder: public ASTWalker
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::map<std::string, FunctionDefinition const*> const& inlinableFunctions() const
|
std::map<YulString, FunctionDefinition const*> const& inlinableFunctions() const
|
||||||
{
|
{
|
||||||
return m_inlinableFunctions;
|
return m_inlinableFunctions;
|
||||||
}
|
}
|
||||||
@ -54,15 +54,15 @@ public:
|
|||||||
virtual void operator()(FunctionDefinition const& _function) override;
|
virtual void operator()(FunctionDefinition const& _function) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkAllowed(std::string const& _name)
|
void checkAllowed(YulString _name)
|
||||||
{
|
{
|
||||||
if (m_disallowedIdentifiers.count(_name))
|
if (m_disallowedIdentifiers.count(_name))
|
||||||
m_foundDisallowedIdentifier = true;
|
m_foundDisallowedIdentifier = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_foundDisallowedIdentifier = false;
|
bool m_foundDisallowedIdentifier = false;
|
||||||
std::set<std::string> m_disallowedIdentifiers;
|
std::set<YulString> m_disallowedIdentifiers;
|
||||||
std::map<std::string, FunctionDefinition const*> m_inlinableFunctions;
|
std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,12 @@ void MainFunction::operator()(Block& _block)
|
|||||||
for (size_t i = 1; i < _block.statements.size(); ++i)
|
for (size_t i = 1; i < _block.statements.size(); ++i)
|
||||||
assertThrow(_block.statements.at(i).type() == typeid(FunctionDefinition), OptimizerException, "");
|
assertThrow(_block.statements.at(i).type() == typeid(FunctionDefinition), OptimizerException, "");
|
||||||
/// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function
|
/// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function
|
||||||
assertThrow(NameCollector(_block).names().count("main") == 0, OptimizerException, "");
|
assertThrow(NameCollector(_block).names().count(YulString{"main"}) == 0, OptimizerException, "");
|
||||||
|
|
||||||
Block& block = boost::get<Block>(_block.statements[0]);
|
Block& block = boost::get<Block>(_block.statements[0]);
|
||||||
FunctionDefinition main{
|
FunctionDefinition main{
|
||||||
block.location,
|
block.location,
|
||||||
"main",
|
YulString{"main"},
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
std::move(block)
|
std::move(block)
|
||||||
|
@ -29,16 +29,16 @@ using namespace dev::yul;
|
|||||||
void NameCollector::operator()(VariableDeclaration const& _varDecl)
|
void NameCollector::operator()(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
for (auto const& var: _varDecl.variables)
|
for (auto const& var: _varDecl.variables)
|
||||||
m_names.insert(var.name);
|
m_names.emplace(var.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NameCollector::operator ()(FunctionDefinition const& _funDef)
|
void NameCollector::operator ()(FunctionDefinition const& _funDef)
|
||||||
{
|
{
|
||||||
m_names.insert(_funDef.name);
|
m_names.emplace(_funDef.name);
|
||||||
for (auto const arg: _funDef.parameters)
|
for (auto const arg: _funDef.parameters)
|
||||||
m_names.insert(arg.name);
|
m_names.emplace(arg.name);
|
||||||
for (auto const ret: _funDef.returnVariables)
|
for (auto const ret: _funDef.returnVariables)
|
||||||
m_names.insert(ret.name);
|
m_names.emplace(ret.name);
|
||||||
ASTWalker::operator ()(_funDef);
|
ASTWalker::operator ()(_funDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,14 +53,14 @@ void ReferencesCounter::operator()(FunctionCall const& _funCall)
|
|||||||
ASTWalker::operator()(_funCall);
|
ASTWalker::operator()(_funCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<string, size_t> ReferencesCounter::countReferences(Block const& _block)
|
map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block)
|
||||||
{
|
{
|
||||||
ReferencesCounter counter;
|
ReferencesCounter counter;
|
||||||
counter(_block);
|
counter(_block);
|
||||||
return counter.references();
|
return counter.references();
|
||||||
}
|
}
|
||||||
|
|
||||||
map<string, size_t> ReferencesCounter::countReferences(Expression const& _expression)
|
map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression)
|
||||||
{
|
{
|
||||||
ReferencesCounter counter;
|
ReferencesCounter counter;
|
||||||
counter.visit(_expression);
|
counter.visit(_expression);
|
||||||
@ -70,5 +70,5 @@ map<string, size_t> ReferencesCounter::countReferences(Expression const& _expres
|
|||||||
void Assignments::operator()(Assignment const& _assignment)
|
void Assignments::operator()(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
for (auto const& var: _assignment.variableNames)
|
for (auto const& var: _assignment.variableNames)
|
||||||
m_names.insert(var.name);
|
m_names.emplace(var.name);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -46,9 +45,9 @@ public:
|
|||||||
virtual void operator()(VariableDeclaration const& _varDecl) override;
|
virtual void operator()(VariableDeclaration const& _varDecl) override;
|
||||||
virtual void operator()(FunctionDefinition const& _funDef) override;
|
virtual void operator()(FunctionDefinition const& _funDef) override;
|
||||||
|
|
||||||
std::set<std::string> names() const { return m_names; }
|
std::set<YulString> names() const { return m_names; }
|
||||||
private:
|
private:
|
||||||
std::set<std::string> m_names;
|
std::set<YulString> m_names;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,12 +60,12 @@ public:
|
|||||||
virtual void operator()(Identifier const& _identifier);
|
virtual void operator()(Identifier const& _identifier);
|
||||||
virtual void operator()(FunctionCall const& _funCall);
|
virtual void operator()(FunctionCall const& _funCall);
|
||||||
|
|
||||||
static std::map<std::string, size_t> countReferences(Block const& _block);
|
static std::map<YulString, size_t> countReferences(Block const& _block);
|
||||||
static std::map<std::string, size_t> countReferences(Expression const& _expression);
|
static std::map<YulString, size_t> countReferences(Expression const& _expression);
|
||||||
|
|
||||||
std::map<std::string, size_t> const& references() const { return m_references; }
|
std::map<YulString, size_t> const& references() const { return m_references; }
|
||||||
private:
|
private:
|
||||||
std::map<std::string, size_t> m_references;
|
std::map<YulString, size_t> m_references;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,9 +77,9 @@ public:
|
|||||||
using ASTWalker::operator ();
|
using ASTWalker::operator ();
|
||||||
virtual void operator()(Assignment const& _assignment) override;
|
virtual void operator()(Assignment const& _assignment) override;
|
||||||
|
|
||||||
std::set<std::string> const& names() const { return m_names; }
|
std::set<YulString> const& names() const { return m_names; }
|
||||||
private:
|
private:
|
||||||
std::set<std::string> m_names;
|
std::set<YulString> m_names;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,31 +33,31 @@ NameDispenser::NameDispenser(Block const& _ast):
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NameDispenser::NameDispenser(set<string> _usedNames):
|
NameDispenser::NameDispenser(set<YulString> _usedNames):
|
||||||
m_usedNames(std::move(_usedNames))
|
m_usedNames(std::move(_usedNames))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
string NameDispenser::newName(string const& _nameHint, string const& _context)
|
YulString NameDispenser::newName(YulString _nameHint, YulString _context)
|
||||||
{
|
{
|
||||||
// Shortening rules: Use a suffix of _prefix and a prefix of _context.
|
// Shortening rules: Use a suffix of _prefix and a prefix of _context.
|
||||||
string prefix = _nameHint;
|
YulString prefix = _nameHint;
|
||||||
|
|
||||||
if (!_context.empty())
|
if (!_context.empty())
|
||||||
prefix = _context.substr(0, 10) + "_" + prefix;
|
prefix = YulString{_context.str().substr(0, 10) + "_" + prefix.str()};
|
||||||
|
|
||||||
return newNameInternal(prefix);
|
return newNameInternal(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
string NameDispenser::newNameInternal(string const& _nameHint)
|
YulString NameDispenser::newNameInternal(YulString _nameHint)
|
||||||
{
|
{
|
||||||
|
YulString name = _nameHint;
|
||||||
size_t suffix = 0;
|
size_t suffix = 0;
|
||||||
string name = _nameHint;
|
|
||||||
while (name.empty() || m_usedNames.count(name))
|
while (name.empty() || m_usedNames.count(name))
|
||||||
{
|
{
|
||||||
suffix++;
|
suffix++;
|
||||||
name = _nameHint + "_" + to_string(suffix);
|
name = YulString(_nameHint.str() + "_" + to_string(suffix));
|
||||||
}
|
}
|
||||||
m_usedNames.insert(name);
|
m_usedNames.emplace(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,9 @@
|
|||||||
|
|
||||||
#include <libyul/ASTDataForward.h>
|
#include <libyul/ASTDataForward.h>
|
||||||
|
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -41,18 +42,18 @@ public:
|
|||||||
/// Initialize the name dispenser with all the names used in the given AST.
|
/// Initialize the name dispenser with all the names used in the given AST.
|
||||||
explicit NameDispenser(Block const& _ast);
|
explicit NameDispenser(Block const& _ast);
|
||||||
/// Initialize the name dispenser with the given used names.
|
/// Initialize the name dispenser with the given used names.
|
||||||
explicit NameDispenser(std::set<std::string> _usedNames);
|
explicit NameDispenser(std::set<YulString> _usedNames);
|
||||||
|
|
||||||
/// @returns a currently unused name that should be similar to _nameHint
|
/// @returns a currently unused name that should be similar to _nameHint
|
||||||
/// and prefixed by _context if present.
|
/// and prefixed by _context if present.
|
||||||
/// If the resulting name would be too long, trims the context at the end
|
/// If the resulting name would be too long, trims the context at the end
|
||||||
/// and the name hint at the start.
|
/// and the name hint at the start.
|
||||||
std::string newName(std::string const& _nameHint, std::string const& _context = {});
|
YulString newName(YulString _nameHint, YulString _context = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string newNameInternal(std::string const& _nameHint);
|
YulString newNameInternal(YulString _nameHint);
|
||||||
|
|
||||||
std::set<std::string> m_usedNames;
|
std::set<YulString> m_usedNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableD
|
|||||||
ASTWalker::operator()(_variableDeclaration);
|
ASTWalker::operator()(_variableDeclaration);
|
||||||
|
|
||||||
for (auto const& var: _variableDeclaration.variables)
|
for (auto const& var: _variableDeclaration.variables)
|
||||||
m_declaredVariables.insert(var.name);
|
m_declaredVariables.emplace(var.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Assignment const& _assignment)
|
void RedundantAssignEliminator::operator()(Assignment const& _assignment)
|
||||||
@ -156,7 +156,7 @@ void RedundantAssignEliminator::run(Block& _ast)
|
|||||||
{
|
{
|
||||||
assertThrow(assignment.second != State::Undecided, OptimizerException, "");
|
assertThrow(assignment.second != State::Undecided, OptimizerException, "");
|
||||||
if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable())
|
if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable())
|
||||||
assignmentsToRemove.insert(assignment.first);
|
assignmentsToRemove.emplace(assignment.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssignmentRemover remover{assignmentsToRemove};
|
AssignmentRemover remover{assignmentsToRemove};
|
||||||
@ -176,7 +176,7 @@ void RedundantAssignEliminator::join(RedundantAssignEliminator& _other)
|
|||||||
m_assignments[var.first] = std::move(var.second);
|
m_assignments[var.first] = std::move(var.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::changeUndecidedTo(string const& _variable, RedundantAssignEliminator::State _newState)
|
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
|
||||||
{
|
{
|
||||||
for (auto& assignment: m_assignments[_variable])
|
for (auto& assignment: m_assignments[_variable])
|
||||||
if (assignment.second == State{State::Undecided})
|
if (assignment.second == State{State::Undecided})
|
||||||
|
@ -125,9 +125,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
enum Value { Unused, Undecided, Used };
|
enum Value { Unused, Undecided, Used };
|
||||||
State(Value _value = Undecided): m_value(_value) {}
|
State(Value _value = Undecided): m_value(_value) {}
|
||||||
bool operator==(State _other) const { return m_value == _other.m_value; }
|
inline bool operator==(State _other) const { return m_value == _other.m_value; }
|
||||||
bool operator!=(State _other) const { return !operator==(_other); }
|
inline bool operator!=(State _other) const { return !operator==(_other); }
|
||||||
void join(State _other)
|
inline void join(State const& _other)
|
||||||
{
|
{
|
||||||
// Using "max" works here because of the order of the values in the enum.
|
// Using "max" works here because of the order of the values in the enum.
|
||||||
m_value = Value(std::max(int(_other.m_value), int(m_value)));
|
m_value = Value(std::max(int(_other.m_value), int(m_value)));
|
||||||
@ -156,17 +156,18 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
RedundantAssignEliminator& m_rae;
|
RedundantAssignEliminator& m_rae;
|
||||||
std::set<std::string> m_outerDeclaredVariables;
|
std::set<YulString> m_outerDeclaredVariables;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Joins the assignment mapping with @a _other according to the rules laid out
|
/// Joins the assignment mapping with @a _other according to the rules laid out
|
||||||
/// above.
|
/// above.
|
||||||
/// Will destroy @a _other.
|
/// Will destroy @a _other.
|
||||||
void join(RedundantAssignEliminator& _other);
|
void join(RedundantAssignEliminator& _other);
|
||||||
void changeUndecidedTo(std::string const& _variable, State _newState);
|
void changeUndecidedTo(YulString _variable, State _newState);
|
||||||
|
|
||||||
std::set<std::string> m_declaredVariables;
|
std::set<YulString> m_declaredVariables;
|
||||||
std::map<std::string, std::map<Assignment const*, State>> m_assignments;
|
// TODO check that this does not cause nondeterminism!
|
||||||
|
std::map<YulString, std::map<Assignment const*, State>> m_assignments;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssignmentRemover: public ASTModifier
|
class AssignmentRemover: public ASTModifier
|
||||||
|
@ -37,7 +37,7 @@ void Rematerialiser::visit(Expression& _e)
|
|||||||
Identifier& identifier = boost::get<Identifier>(_e);
|
Identifier& identifier = boost::get<Identifier>(_e);
|
||||||
if (m_value.count(identifier.name))
|
if (m_value.count(identifier.name))
|
||||||
{
|
{
|
||||||
string name = identifier.name;
|
YulString name = identifier.name;
|
||||||
for (auto const& ref: m_references[name])
|
for (auto const& ref: m_references[name])
|
||||||
assertThrow(inScope(ref), OptimizerException, "");
|
assertThrow(inScope(ref), OptimizerException, "");
|
||||||
assertThrow(m_value.at(name), OptimizerException, "");
|
assertThrow(m_value.at(name), OptimizerException, "");
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
namespace yul
|
namespace yul
|
||||||
|
@ -62,15 +62,15 @@ void SSATransform::operator()(ForLoop& _for)
|
|||||||
|
|
||||||
void SSATransform::operator()(Block& _block)
|
void SSATransform::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
set<string> variablesToClearAtEnd;
|
set<YulString> variablesToClearAtEnd;
|
||||||
|
|
||||||
// Creates a new variable (and returns its declaration) with value _value
|
// Creates a new variable (and returns its declaration) with value _value
|
||||||
// and replaces _value by a reference to that new variable.
|
// and replaces _value by a reference to that new variable.
|
||||||
auto replaceByNew = [&](SourceLocation _loc, string _varName, string _type, shared_ptr<Expression>& _value) -> VariableDeclaration
|
auto replaceByNew = [&](SourceLocation _loc, YulString _varName, YulString _type, shared_ptr<Expression>& _value) -> VariableDeclaration
|
||||||
{
|
{
|
||||||
string newName = m_nameDispenser.newName(_varName);
|
YulString newName = m_nameDispenser.newName(_varName);
|
||||||
m_currentVariableValues[_varName] = newName;
|
m_currentVariableValues[_varName] = newName;
|
||||||
variablesToClearAtEnd.insert(_varName);
|
variablesToClearAtEnd.emplace(_varName);
|
||||||
shared_ptr<Expression> v = make_shared<Expression>(Identifier{_loc, newName});
|
shared_ptr<Expression> v = make_shared<Expression>(Identifier{_loc, newName});
|
||||||
_value.swap(v);
|
_value.swap(v);
|
||||||
return VariableDeclaration{_loc, {TypedName{_loc, std::move(newName), std::move(_type)}}, std::move(v)};
|
return VariableDeclaration{_loc, {TypedName{_loc, std::move(newName), std::move(_type)}}, std::move(v)};
|
||||||
|
@ -85,13 +85,13 @@ public:
|
|||||||
static void run(Block& _ast, NameDispenser& _nameDispenser);
|
static void run(Block& _ast, NameDispenser& _nameDispenser);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SSATransform(NameDispenser& _nameDispenser, std::set<std::string> const& _variablesToReplace):
|
explicit SSATransform(NameDispenser& _nameDispenser, std::set<YulString> const& _variablesToReplace):
|
||||||
m_nameDispenser(_nameDispenser), m_variablesToReplace(_variablesToReplace)
|
m_nameDispenser(_nameDispenser), m_variablesToReplace(_variablesToReplace)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
NameDispenser& m_nameDispenser;
|
NameDispenser& m_nameDispenser;
|
||||||
std::set<std::string> const& m_variablesToReplace;
|
std::set<YulString> const& m_variablesToReplace;
|
||||||
std::map<std::string, std::string> m_currentVariableValues;
|
std::map<YulString, YulString> m_currentVariableValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl)
|
|||||||
setValue(var.name, nullptr);
|
setValue(var.name, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSAValueTracker::setValue(string const& _name, Expression const* _value)
|
void SSAValueTracker::setValue(YulString _name, Expression const* _value)
|
||||||
{
|
{
|
||||||
assertThrow(
|
assertThrow(
|
||||||
m_values.count(_name) == 0,
|
m_values.count(_name) == 0,
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -45,13 +44,13 @@ public:
|
|||||||
virtual void operator()(VariableDeclaration const& _varDecl) override;
|
virtual void operator()(VariableDeclaration const& _varDecl) override;
|
||||||
virtual void operator()(Assignment const& _assignment) override;
|
virtual void operator()(Assignment const& _assignment) override;
|
||||||
|
|
||||||
std::map<std::string, Expression const*> const& values() const { return m_values; }
|
std::map<YulString, Expression const*> const& values() const { return m_values; }
|
||||||
Expression const* value(std::string const& _name) const { return m_values.at(_name); }
|
Expression const* value(YulString _name) const { return m_values.at(_name); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setValue(std::string const& _name, Expression const* _value);
|
void setValue(YulString _name, Expression const* _value);
|
||||||
|
|
||||||
std::map<std::string, Expression const*> m_values;
|
std::map<YulString, Expression const*> m_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ MovableChecker::MovableChecker(Expression const& _expression)
|
|||||||
void MovableChecker::operator()(Identifier const& _identifier)
|
void MovableChecker::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
ASTWalker::operator()(_identifier);
|
ASTWalker::operator()(_identifier);
|
||||||
m_variableReferences.insert(_identifier.name);
|
m_variableReferences.emplace(_identifier.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovableChecker::operator()(FunctionalInstruction const& _instr)
|
void MovableChecker::operator()(FunctionalInstruction const& _instr)
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -49,11 +47,11 @@ public:
|
|||||||
using ASTWalker::visit;
|
using ASTWalker::visit;
|
||||||
|
|
||||||
bool movable() const { return m_movable; }
|
bool movable() const { return m_movable; }
|
||||||
std::set<std::string> const& referencedVariables() const { return m_variableReferences; }
|
std::set<YulString> const& referencedVariables() const { return m_variableReferences; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Which variables the current expression references.
|
/// Which variables the current expression references.
|
||||||
std::set<std::string> m_variableReferences;
|
std::set<YulString> m_variableReferences;
|
||||||
/// Is the current expression movable or not.
|
/// Is the current expression movable or not.
|
||||||
bool m_movable = true;
|
bool m_movable = true;
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@ using namespace dev::yul;
|
|||||||
|
|
||||||
SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
|
SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
map<string, Expression const*> const& _ssaValues
|
map<YulString, Expression const*> const& _ssaValues
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (_expr.type() != typeid(FunctionalInstruction))
|
if (_expr.type() != typeid(FunctionalInstruction))
|
||||||
@ -104,7 +104,7 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _
|
|||||||
m_matchGroups = &_matchGroups;
|
m_matchGroups = &_matchGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pattern::matches(Expression const& _expr, map<string, Expression const*> const& _ssaValues) const
|
bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*> const& _ssaValues) const
|
||||||
{
|
{
|
||||||
Expression const* expr = &_expr;
|
Expression const* expr = &_expr;
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co
|
|||||||
// Do not do it for "Any" because we can check identity better for variables.
|
// Do not do it for "Any" because we can check identity better for variables.
|
||||||
if (m_kind != PatternKind::Any && _expr.type() == typeid(Identifier))
|
if (m_kind != PatternKind::Any && _expr.type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
string const& varName = boost::get<Identifier>(_expr).name;
|
YulString varName = boost::get<Identifier>(_expr).name;
|
||||||
if (_ssaValues.count(varName))
|
if (_ssaValues.count(varName))
|
||||||
expr = _ssaValues.at(varName);
|
expr = _ssaValues.at(varName);
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co
|
|||||||
Literal const& literal = boost::get<Literal>(*expr);
|
Literal const& literal = boost::get<Literal>(*expr);
|
||||||
if (literal.kind != assembly::LiteralKind::Number)
|
if (literal.kind != assembly::LiteralKind::Number)
|
||||||
return false;
|
return false;
|
||||||
if (m_data && *m_data != u256(literal.value))
|
if (m_data && *m_data != u256(literal.value.str()))
|
||||||
return false;
|
return false;
|
||||||
assertThrow(m_arguments.empty(), OptimizerException, "");
|
assertThrow(m_arguments.empty(), OptimizerException, "");
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
|
|||||||
if (m_kind == PatternKind::Constant)
|
if (m_kind == PatternKind::Constant)
|
||||||
{
|
{
|
||||||
assertThrow(m_data, OptimizerException, "No match group and no constant value given.");
|
assertThrow(m_data, OptimizerException, "No match group and no constant value given.");
|
||||||
return Literal{_location, assembly::LiteralKind::Number, formatNumber(*m_data), ""};
|
return Literal{_location, assembly::LiteralKind::Number, YulString{formatNumber(*m_data)}, {}};
|
||||||
}
|
}
|
||||||
else if (m_kind == PatternKind::Operation)
|
else if (m_kind == PatternKind::Operation)
|
||||||
{
|
{
|
||||||
@ -209,8 +209,8 @@ u256 Pattern::d() const
|
|||||||
{
|
{
|
||||||
Literal const& literal = boost::get<Literal>(matchGroupValue());
|
Literal const& literal = boost::get<Literal>(matchGroupValue());
|
||||||
assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, "");
|
assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, "");
|
||||||
assertThrow(isValidDecimal(literal.value) || isValidHex(literal.value), OptimizerException, "");
|
assertThrow(isValidDecimal(literal.value.str()) || isValidHex(literal.value.str()), OptimizerException, "");
|
||||||
return u256(literal.value);
|
return u256(literal.value.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression const& Pattern::matchGroupValue() const
|
Expression const& Pattern::matchGroupValue() const
|
||||||
|
@ -52,7 +52,7 @@ public:
|
|||||||
/// @param _ssaValues values of variables that are assigned exactly once.
|
/// @param _ssaValues values of variables that are assigned exactly once.
|
||||||
static SimplificationRule<Pattern> const* findFirstMatch(
|
static SimplificationRule<Pattern> const* findFirstMatch(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
std::map<std::string, Expression const*> const& _ssaValues
|
std::map<YulString, Expression const*> const& _ssaValues
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Checks whether the rulelist is non-empty. This is usually enforced
|
/// Checks whether the rulelist is non-empty. This is usually enforced
|
||||||
@ -96,7 +96,7 @@ public:
|
|||||||
/// same expression equivalence class.
|
/// same expression equivalence class.
|
||||||
void setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups);
|
void setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups);
|
||||||
unsigned matchGroup() const { return m_matchGroup; }
|
unsigned matchGroup() const { return m_matchGroup; }
|
||||||
bool matches(Expression const& _expr, std::map<std::string, Expression const*> const& _ssaValues) const;
|
bool matches(Expression const& _expr, std::map<YulString, Expression const*> const& _ssaValues) const;
|
||||||
|
|
||||||
std::vector<Pattern> arguments() const { return m_arguments; }
|
std::vector<Pattern> arguments() const { return m_arguments; }
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ Expression Substitution::translate(Expression const& _expression)
|
|||||||
{
|
{
|
||||||
if (_expression.type() == typeid(Identifier))
|
if (_expression.type() == typeid(Identifier))
|
||||||
{
|
{
|
||||||
string const& name = boost::get<Identifier>(_expression).name;
|
YulString name = boost::get<Identifier>(_expression).name;
|
||||||
if (m_substitutions.count(name))
|
if (m_substitutions.count(name))
|
||||||
// No recursive substitution
|
// No recursive substitution
|
||||||
return ASTCopier().translate(*m_substitutions.at(name));
|
return ASTCopier().translate(*m_substitutions.at(name));
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ASTCopier.h>
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
|
|
||||||
#include <string>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
@ -37,13 +37,13 @@ namespace yul
|
|||||||
class Substitution: public ASTCopier
|
class Substitution: public ASTCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Substitution(std::map<std::string, Expression const*> const& _substitutions):
|
Substitution(std::map<YulString, Expression const*> const& _substitutions):
|
||||||
m_substitutions(_substitutions)
|
m_substitutions(_substitutions)
|
||||||
{}
|
{}
|
||||||
virtual Expression translate(Expression const& _expression) override;
|
virtual Expression translate(Expression const& _expression) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, Expression const*> const& m_substitutions;
|
std::map<YulString, Expression const*> const& m_substitutions;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,10 @@ using namespace dev::yul;
|
|||||||
void OptimiserSuite::run(
|
void OptimiserSuite::run(
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
||||||
set<string> const& _externallyUsedIdentifiers
|
set<YulString> const& _externallyUsedIdentifiers
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
set<string> reservedIdentifiers = _externallyUsedIdentifiers;
|
set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
|
||||||
|
|
||||||
Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast));
|
Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast));
|
||||||
|
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/ASTDataForward.h>
|
#include <libyul/ASTDataForward.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -47,7 +46,8 @@ public:
|
|||||||
static void run(
|
static void run(
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
|
||||||
std::set<std::string> const& _externallyUsedIdentifiers = std::set<std::string>()
|
|
||||||
|
std::set<YulString> const& _externallyUsedIdentifiers = {}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const&
|
|||||||
{
|
{
|
||||||
if (_e1.type() != _e2.type())
|
if (_e1.type() != _e2.type())
|
||||||
return false;
|
return false;
|
||||||
|
// TODO This somehow calls strcmp - WHERE?
|
||||||
|
|
||||||
// TODO This should be replaced by some kind of AST walker as soon as it gets
|
// TODO This should be replaced by some kind of AST walker as soon as it gets
|
||||||
// more complex.
|
// more complex.
|
||||||
|
@ -33,7 +33,7 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::yul;
|
using namespace dev::yul;
|
||||||
|
|
||||||
UnusedPruner::UnusedPruner(Block& _ast, set<string> const& _externallyUsedFunctions)
|
UnusedPruner::UnusedPruner(Block& _ast, set<YulString> const& _externallyUsedFunctions)
|
||||||
{
|
{
|
||||||
ReferencesCounter counter;
|
ReferencesCounter counter;
|
||||||
counter(_ast);
|
counter(_ast);
|
||||||
@ -91,7 +91,7 @@ void UnusedPruner::operator()(Block& _block)
|
|||||||
ASTModifier::operator()(_block);
|
ASTModifier::operator()(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externallyUsedFunctions)
|
void UnusedPruner::runUntilStabilised(Block& _ast, set<YulString> const& _externallyUsedFunctions)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -102,12 +102,12 @@ void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externall
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnusedPruner::used(string const& _name) const
|
bool UnusedPruner::used(YulString _name) const
|
||||||
{
|
{
|
||||||
return m_references.count(_name) && m_references.at(_name) > 0;
|
return m_references.count(_name) && m_references.at(_name) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnusedPruner::subtractReferences(map<string, size_t> const& _subtrahend)
|
void UnusedPruner::subtractReferences(map<YulString, size_t> const& _subtrahend)
|
||||||
{
|
{
|
||||||
for (auto const& ref: _subtrahend)
|
for (auto const& ref: _subtrahend)
|
||||||
{
|
{
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ namespace yul
|
|||||||
class UnusedPruner: public ASTModifier
|
class UnusedPruner: public ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit UnusedPruner(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
|
explicit UnusedPruner(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {});
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
virtual void operator()(Block& _block) override;
|
virtual void operator()(Block& _block) override;
|
||||||
@ -53,14 +53,14 @@ public:
|
|||||||
bool shouldRunAgain() const { return m_shouldRunAgain; }
|
bool shouldRunAgain() const { return m_shouldRunAgain; }
|
||||||
|
|
||||||
// Run the pruner until the code does not change anymore.
|
// Run the pruner until the code does not change anymore.
|
||||||
static void runUntilStabilised(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
|
static void runUntilStabilised(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool used(std::string const& _name) const;
|
bool used(YulString _name) const;
|
||||||
void subtractReferences(std::map<std::string, size_t> const& _subtrahend);
|
void subtractReferences(std::map<YulString, size_t> const& _subtrahend);
|
||||||
|
|
||||||
bool m_shouldRunAgain = false;
|
bool m_shouldRunAgain = false;
|
||||||
std::map<std::string, size_t> m_references;
|
std::map<YulString, size_t> m_references;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ using dev::solidity::assembly::TypedNameList;
|
|||||||
|
|
||||||
void VarDeclPropagator::operator()(Block& _block)
|
void VarDeclPropagator::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
map<string, TypedName> outerEmptyVarDecls;
|
map<YulString, TypedName> outerEmptyVarDecls;
|
||||||
map<string, TypedName> outerLazyInitializedVarDecls;
|
map<YulString, TypedName> outerLazyInitializedVarDecls;
|
||||||
swap(m_emptyVarDecls, outerEmptyVarDecls);
|
swap(m_emptyVarDecls, outerEmptyVarDecls);
|
||||||
swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls);
|
swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls);
|
||||||
|
|
||||||
|
@ -53,10 +53,10 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
/// Holds a list of variables from current Block that have no value assigned yet.
|
/// Holds a list of variables from current Block that have no value assigned yet.
|
||||||
std::map<std::string, TypedName> m_emptyVarDecls;
|
std::map<YulString, TypedName> m_emptyVarDecls;
|
||||||
|
|
||||||
/// Holds a list variables (and their TypedName) within the current block.
|
/// Holds a list variables (and their TypedName) within the current block.
|
||||||
std::map<std::string, TypedName> m_lazyInitializedVarDecls;
|
std::map<YulString, TypedName> m_lazyInitializedVarDecls;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,10 @@ string inlinableFunctions(string const& _source)
|
|||||||
InlinableExpressionFunctionFinder funFinder;
|
InlinableExpressionFunctionFinder funFinder;
|
||||||
funFinder(ast);
|
funFinder(ast);
|
||||||
|
|
||||||
return boost::algorithm::join(
|
vector<string> functionNames;
|
||||||
funFinder.inlinableFunctions() | boost::adaptors::map_keys,
|
for (auto const& f: funFinder.inlinableFunctions())
|
||||||
","
|
functionNames.emplace_back(f.first.str());
|
||||||
);
|
return boost::algorithm::join(functionNames, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user