mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7760 from ethereum/merge_develop_060
Merge develop into develop_060
This commit is contained in:
commit
1b9e861050
@ -52,8 +52,8 @@ then
|
|||||||
rm -rf z3-4.8.6-x64-osx-10.14.6
|
rm -rf z3-4.8.6-x64-osx-10.14.6
|
||||||
|
|
||||||
# evmone
|
# evmone
|
||||||
wget https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-darwin-x86_64.tar.gz
|
wget https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-darwin-x86_64.tar.gz
|
||||||
tar xzpf evmone-0.1.0-darwin-x86_64.tar.gz -C /usr/local
|
tar xzpf evmone-0.3.0-darwin-x86_64.tar.gz -C /usr/local
|
||||||
rm -f evmone-0.1.0-darwin-x86_64.tar.gz
|
rm -f evmone-0.3.0-darwin-x86_64.tar.gz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ set -e
|
|||||||
REPODIR="$(realpath $(dirname $0)/..)"
|
REPODIR="$(realpath $(dirname $0)/..)"
|
||||||
|
|
||||||
for OPTIMIZE in 0 1; do
|
for OPTIMIZE in 0 1; do
|
||||||
for EVM in homestead byzantium constantinople petersburg; do
|
for EVM in homestead byzantium constantinople petersburg istanbul; do
|
||||||
EVM=$EVM OPTIMIZE=$OPTIMIZE ${REPODIR}/.circleci/soltest.sh
|
EVM=$EVM OPTIMIZE=$OPTIMIZE ${REPODIR}/.circleci/soltest.sh
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
17
.github/workflows/stale.yml
vendored
17
.github/workflows/stale.yml
vendored
@ -1,17 +0,0 @@
|
|||||||
name: Mark stale pull requests
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v1
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
stale-pr-message: "A reminder that this pull request has had no activity for 14 days"
|
|
||||||
stale-pr-label: "no-pr-activity"
|
|
||||||
days-before-stale: 14
|
|
@ -69,6 +69,7 @@ Bugfixes:
|
|||||||
* SMTChecker: Fix internal error when implicitly converting string literals to fixed bytes.
|
* SMTChecker: Fix internal error when implicitly converting string literals to fixed bytes.
|
||||||
* Type Checker: Disallow constructor of the same class to be used as modifier.
|
* Type Checker: Disallow constructor of the same class to be used as modifier.
|
||||||
* Type Checker: Treat magic variables as unknown identifiers in inline assembly.
|
* Type Checker: Treat magic variables as unknown identifiers in inline assembly.
|
||||||
|
* Code Generator: Fix internal error when trying to convert ``super`` to a different type
|
||||||
|
|
||||||
|
|
||||||
### 0.5.12 (2019-10-01)
|
### 0.5.12 (2019-10-01)
|
||||||
|
@ -94,7 +94,7 @@ The test system will automatically try to discover the location of the ``evmone`
|
|||||||
starting from the current directory. The required file is called ``libevmone.so`` on Linux systems,
|
starting from the current directory. The required file is called ``libevmone.so`` on Linux systems,
|
||||||
``evmone.dll`` on Windows systems and ``libevmone.dylib`` on MacOS. If it is not found, the relevant tests
|
``evmone.dll`` on Windows systems and ``libevmone.dylib`` on MacOS. If it is not found, the relevant tests
|
||||||
are skipped. To run all tests, download the library from
|
are skipped. To run all tests, download the library from
|
||||||
`Github <https://github.com/ethereum/evmone/releases/tag/v0.1.0>`_
|
`Github <https://github.com/ethereum/evmone/releases/tag/v0.3.0>`_
|
||||||
and either place it in the project root path or inside the ``deps`` folder.
|
and either place it in the project root path or inside the ``deps`` folder.
|
||||||
|
|
||||||
If you do not have libz3 installed on your system, you should disable the SMT tests:
|
If you do not have libz3 installed on your system, you should disable the SMT tests:
|
||||||
|
@ -185,11 +185,17 @@ introduce new identifiers into these scopes.
|
|||||||
|
|
||||||
Identifiers are visible in
|
Identifiers are visible in
|
||||||
the block they are defined in (including all sub-nodes and sub-blocks).
|
the block they are defined in (including all sub-nodes and sub-blocks).
|
||||||
As an exception, identifiers defined in the "init" part of the for-loop
|
|
||||||
|
As an exception, identifiers defined directly in the "init" part of the for-loop
|
||||||
(the first block) are visible in all other parts of the for-loop
|
(the first block) are visible in all other parts of the for-loop
|
||||||
(but not outside of the loop).
|
(but not outside of the loop).
|
||||||
Identifiers declared in the other parts of the for loop respect the regular
|
Identifiers declared in the other parts of the for loop respect the regular
|
||||||
syntactical scoping rules.
|
syntactical scoping rules.
|
||||||
|
|
||||||
|
This means a for-loop of the form ``for { I... } C { P... } { B... }`` is equivalent
|
||||||
|
to ``{ I... for {} C { P... } { B... } }``.
|
||||||
|
|
||||||
|
|
||||||
The parameters and return parameters of functions are visible in the
|
The parameters and return parameters of functions are visible in the
|
||||||
function body and their names cannot overlap.
|
function body and their names cannot overlap.
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ namespace dev
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// Generic visitor used as follows:
|
/// Generic visitor used as follows:
|
||||||
/// boost::apply_visitor(GenericVisitor<Class1, Class2>(
|
/// std::visit(GenericVisitor<Class1, Class2>(
|
||||||
/// [](Class1& _c) { _c.f(); },
|
/// [](Class1& _c) { _c.f(); },
|
||||||
/// [](Class2& _c) { _c.g(); }
|
/// [](Class2& _c) { _c.g(); }
|
||||||
/// ), variant);
|
/// ), variant);
|
||||||
@ -59,7 +59,7 @@ struct GenericVisitor<>: public boost::static_visitor<> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Generic visitor with fallback:
|
/// Generic visitor with fallback:
|
||||||
/// boost::apply_visitor(GenericFallbackVisitor<Class1, Class2>(
|
/// std::visit(GenericFallbackVisitor<Class1, Class2>(
|
||||||
/// [](Class1& _c) { _c.f(); },
|
/// [](Class1& _c) { _c.f(); },
|
||||||
/// [](Class2& _c) { _c.g(); }
|
/// [](Class2& _c) { _c.g(); }
|
||||||
/// ), variant);
|
/// ), variant);
|
||||||
@ -92,7 +92,7 @@ struct GenericFallbackVisitor<>: public boost::static_visitor<> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Generic visitor with fallback that can return a value:
|
/// Generic visitor with fallback that can return a value:
|
||||||
/// boost::apply_visitor(GenericFallbackReturnsVisitor<ReturnType, Class1, Class2>(
|
/// std::visit(GenericFallbackReturnsVisitor<ReturnType, Class1, Class2>(
|
||||||
/// [](Class1& _c) { return _c.f(); },
|
/// [](Class1& _c) { return _c.f(); },
|
||||||
/// [](Class2& _c) { return _c.g(); }
|
/// [](Class2& _c) { return _c.g(); }
|
||||||
/// ), variant);
|
/// ), variant);
|
||||||
|
@ -96,7 +96,7 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
|
|||||||
bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
|
bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
|
||||||
{
|
{
|
||||||
assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated.");
|
assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated.");
|
||||||
return bigint(GasMeter::dataGas(_data, m_params.isCreation));
|
return bigint(GasMeter::dataGas(_data, m_params.isCreation, m_params.evmVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
|
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
|
||||||
@ -131,7 +131,7 @@ bigint LiteralMethod::gasNeeded() const
|
|||||||
return combineGas(
|
return combineGas(
|
||||||
simpleRunGas({Instruction::PUSH1}),
|
simpleRunGas({Instruction::PUSH1}),
|
||||||
// PUSHX plus data
|
// PUSHX plus data
|
||||||
(m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)),
|
(m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ bigint CodeCopyMethod::gasNeeded() const
|
|||||||
// Run gas: we ignore memory increase costs
|
// Run gas: we ignore memory increase costs
|
||||||
simpleRunGas(copyRoutine()) + GasCosts::copyGas,
|
simpleRunGas(copyRoutine()) + GasCosts::copyGas,
|
||||||
// Data gas for copy routines: Some bytes are zero, but we ignore them.
|
// Data gas for copy routines: Some bytes are zero, but we ignore them.
|
||||||
bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
|
bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas),
|
||||||
// Data gas for data itself
|
// Data gas for data itself
|
||||||
dataGas(toBigEndian(m_value))
|
dataGas(toBigEndian(m_value))
|
||||||
);
|
);
|
||||||
@ -322,7 +322,7 @@ bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) const
|
|||||||
return combineGas(
|
return combineGas(
|
||||||
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
|
simpleRunGas(_routine) + numExps * (GasCosts::expGas + GasCosts::expByteGas(m_params.evmVersion)),
|
||||||
// Data gas for routine: Some bytes are zero, but we ignore them.
|
// Data gas for routine: Some bytes are zero, but we ignore them.
|
||||||
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas : GasCosts::createDataGas),
|
bytesRequired(_routine) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -266,13 +266,13 @@ unsigned GasMeter::runGas(Instruction _instruction)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 GasMeter::dataGas(bytes const& _data, bool _inCreation)
|
u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion)
|
||||||
{
|
{
|
||||||
bigint gas = 0;
|
bigint gas = 0;
|
||||||
if (_inCreation)
|
if (_inCreation)
|
||||||
{
|
{
|
||||||
for (auto b: _data)
|
for (auto b: _data)
|
||||||
gas += (b != 0) ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas;
|
gas += (b != 0) ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::txDataZeroGas;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gas = bigint(GasCosts::createDataGas) * _data.size();
|
gas = bigint(GasCosts::createDataGas) * _data.size();
|
||||||
|
@ -53,7 +53,12 @@ namespace GasCosts
|
|||||||
}
|
}
|
||||||
inline unsigned balanceGas(langutil::EVMVersion _evmVersion)
|
inline unsigned balanceGas(langutil::EVMVersion _evmVersion)
|
||||||
{
|
{
|
||||||
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 400 : 20;
|
if (_evmVersion >= langutil::EVMVersion::istanbul())
|
||||||
|
return 700;
|
||||||
|
else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle())
|
||||||
|
return 400;
|
||||||
|
else
|
||||||
|
return 20;
|
||||||
}
|
}
|
||||||
static unsigned const expGas = 10;
|
static unsigned const expGas = 10;
|
||||||
inline unsigned expByteGas(langutil::EVMVersion _evmVersion)
|
inline unsigned expByteGas(langutil::EVMVersion _evmVersion)
|
||||||
@ -64,7 +69,12 @@ namespace GasCosts
|
|||||||
static unsigned const keccak256WordGas = 6;
|
static unsigned const keccak256WordGas = 6;
|
||||||
inline unsigned sloadGas(langutil::EVMVersion _evmVersion)
|
inline unsigned sloadGas(langutil::EVMVersion _evmVersion)
|
||||||
{
|
{
|
||||||
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 200 : 50;
|
if (_evmVersion >= langutil::EVMVersion::istanbul())
|
||||||
|
return 800;
|
||||||
|
else if (_evmVersion >= langutil::EVMVersion::tangerineWhistle())
|
||||||
|
return 200;
|
||||||
|
else
|
||||||
|
return 50;
|
||||||
}
|
}
|
||||||
static unsigned const sstoreSetGas = 20000;
|
static unsigned const sstoreSetGas = 20000;
|
||||||
static unsigned const sstoreResetGas = 5000;
|
static unsigned const sstoreResetGas = 5000;
|
||||||
@ -92,7 +102,10 @@ namespace GasCosts
|
|||||||
static unsigned const txGas = 21000;
|
static unsigned const txGas = 21000;
|
||||||
static unsigned const txCreateGas = 53000;
|
static unsigned const txCreateGas = 53000;
|
||||||
static unsigned const txDataZeroGas = 4;
|
static unsigned const txDataZeroGas = 4;
|
||||||
static unsigned const txDataNonZeroGas = 68;
|
inline unsigned txDataNonZeroGas(langutil::EVMVersion _evmVersion)
|
||||||
|
{
|
||||||
|
return _evmVersion >= langutil::EVMVersion::istanbul() ? 16 : 68;
|
||||||
|
}
|
||||||
static unsigned const copyGas = 3;
|
static unsigned const copyGas = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +152,7 @@ public:
|
|||||||
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
|
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
|
||||||
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
|
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
|
||||||
/// otherwise code will be stored and have to pay "createDataGas" cost.
|
/// otherwise code will be stored and have to pay "createDataGas" cost.
|
||||||
static u256 dataGas(bytes const& _data, bool _inCreation);
|
static u256 dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
|
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
#include <libyul/backends/evm/EVMDialect.h>
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <libevmasm/SemanticInformation.h>
|
#include <libevmasm/SemanticInformation.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
@ -31,7 +33,7 @@ using namespace dev::solidity;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
class AssemblyViewPureChecker: public boost::static_visitor<void>
|
class AssemblyViewPureChecker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AssemblyViewPureChecker(
|
explicit AssemblyViewPureChecker(
|
||||||
@ -49,16 +51,16 @@ public:
|
|||||||
void operator()(yul::Identifier const&) {}
|
void operator()(yul::Identifier const&) {}
|
||||||
void operator()(yul::ExpressionStatement const& _expr)
|
void operator()(yul::ExpressionStatement const& _expr)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _expr.expression);
|
std::visit(*this, _expr.expression);
|
||||||
}
|
}
|
||||||
void operator()(yul::Assignment const& _assignment)
|
void operator()(yul::Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, *_assignment.value);
|
std::visit(*this, *_assignment.value);
|
||||||
}
|
}
|
||||||
void operator()(yul::VariableDeclaration const& _varDecl)
|
void operator()(yul::VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
boost::apply_visitor(*this, *_varDecl.value);
|
std::visit(*this, *_varDecl.value);
|
||||||
}
|
}
|
||||||
void operator()(yul::FunctionDefinition const& _funDef)
|
void operator()(yul::FunctionDefinition const& _funDef)
|
||||||
{
|
{
|
||||||
@ -72,16 +74,16 @@ public:
|
|||||||
checkInstruction(_funCall.location, *fun->instruction);
|
checkInstruction(_funCall.location, *fun->instruction);
|
||||||
|
|
||||||
for (auto const& arg: _funCall.arguments)
|
for (auto const& arg: _funCall.arguments)
|
||||||
boost::apply_visitor(*this, arg);
|
std::visit(*this, arg);
|
||||||
}
|
}
|
||||||
void operator()(yul::If const& _if)
|
void operator()(yul::If const& _if)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, *_if.condition);
|
std::visit(*this, *_if.condition);
|
||||||
(*this)(_if.body);
|
(*this)(_if.body);
|
||||||
}
|
}
|
||||||
void operator()(yul::Switch const& _switch)
|
void operator()(yul::Switch const& _switch)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, *_switch.expression);
|
std::visit(*this, *_switch.expression);
|
||||||
for (auto const& _case: _switch.cases)
|
for (auto const& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
if (_case.value)
|
if (_case.value)
|
||||||
@ -92,7 +94,7 @@ public:
|
|||||||
void operator()(yul::ForLoop const& _for)
|
void operator()(yul::ForLoop const& _for)
|
||||||
{
|
{
|
||||||
(*this)(_for.pre);
|
(*this)(_for.pre);
|
||||||
boost::apply_visitor(*this, *_for.condition);
|
std::visit(*this, *_for.condition);
|
||||||
(*this)(_for.body);
|
(*this)(_for.body);
|
||||||
(*this)(_for.post);
|
(*this)(_for.post);
|
||||||
}
|
}
|
||||||
@ -108,7 +110,7 @@ public:
|
|||||||
void operator()(yul::Block const& _block)
|
void operator()(yul::Block const& _block)
|
||||||
{
|
{
|
||||||
for (auto const& s: _block.statements)
|
for (auto const& s: _block.statements)
|
||||||
boost::apply_visitor(*this, s);
|
std::visit(*this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1438,6 +1438,9 @@ Type const* ContractType::encodingType() const
|
|||||||
|
|
||||||
BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
|
if (m_super)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (*this == _convertTo)
|
if (*this == _convertTo)
|
||||||
return true;
|
return true;
|
||||||
if (_convertTo.category() == Category::Contract)
|
if (_convertTo.category() == Category::Contract)
|
||||||
@ -1455,8 +1458,12 @@ BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
|
|
||||||
BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
|
if (m_super)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
|
if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
|
||||||
return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
|
return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
|
||||||
|
|
||||||
return isImplicitlyConvertibleTo(_convertTo);
|
return isImplicitlyConvertibleTo(_convertTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,6 +731,9 @@ void CompilerUtils::convertType(
|
|||||||
Type::Category stackTypeCategory = _typeOnStack.category();
|
Type::Category stackTypeCategory = _typeOnStack.category();
|
||||||
Type::Category targetTypeCategory = _targetType.category();
|
Type::Category targetTypeCategory = _targetType.category();
|
||||||
|
|
||||||
|
if (auto contrType = dynamic_cast<ContractType const*>(&_typeOnStack))
|
||||||
|
solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\"");
|
||||||
|
|
||||||
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
|
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
|
||||||
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
|
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
|
||||||
if (chopSignBitsPending)
|
if (chopSignBitsPending)
|
||||||
|
@ -837,9 +837,9 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
|||||||
|
|
||||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||||
|
|
||||||
solAssert(modified.type() == typeid(yul::Block), "");
|
solAssert(holds_alternative<yul::Block>(modified), "");
|
||||||
|
|
||||||
m_code << yul::AsmPrinter()(boost::get<yul::Block>(std::move(modified))) << "\n";
|
m_code << yul::AsmPrinter()(std::get<yul::Block>(std::move(modified))) << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1457,7 +1457,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
|
|||||||
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
|
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
|
||||||
{
|
{
|
||||||
Gas executionGas = gasEstimator.functionalEstimation(*items);
|
Gas executionGas = gasEstimator.functionalEstimation(*items);
|
||||||
Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false)};
|
Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)};
|
||||||
|
|
||||||
Json::Value creation(Json::objectValue);
|
Json::Value creation(Json::objectValue);
|
||||||
creation["codeDepositCost"] = gasToJson(codeDepositGas);
|
creation["codeDepositCost"] = gasToJson(codeDepositGas);
|
||||||
|
@ -182,7 +182,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier)
|
|||||||
bool AsmAnalyzer::operator()(ExpressionStatement const& _statement)
|
bool AsmAnalyzer::operator()(ExpressionStatement const& _statement)
|
||||||
{
|
{
|
||||||
int initialStackHeight = m_stackHeight;
|
int initialStackHeight = m_stackHeight;
|
||||||
bool success = boost::apply_visitor(*this, _statement.expression);
|
bool success = std::visit(*this, _statement.expression);
|
||||||
if (success && m_stackHeight != initialStackHeight)
|
if (success && m_stackHeight != initialStackHeight)
|
||||||
{
|
{
|
||||||
string msg =
|
string msg =
|
||||||
@ -204,7 +204,7 @@ bool AsmAnalyzer::operator()(Assignment const& _assignment)
|
|||||||
int const expectedItems = _assignment.variableNames.size();
|
int const expectedItems = _assignment.variableNames.size();
|
||||||
solAssert(expectedItems >= 1, "");
|
solAssert(expectedItems >= 1, "");
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
bool success = boost::apply_visitor(*this, *_assignment.value);
|
bool success = std::visit(*this, *_assignment.value);
|
||||||
if ((m_stackHeight - stackHeight) != expectedItems)
|
if ((m_stackHeight - stackHeight) != expectedItems)
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
@ -239,7 +239,7 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
|
|||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
{
|
{
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
success = boost::apply_visitor(*this, *_varDecl.value);
|
success = std::visit(*this, *_varDecl.value);
|
||||||
int numValues = m_stackHeight - stackHeight;
|
int numValues = m_stackHeight - stackHeight;
|
||||||
if (numValues != numVariables)
|
if (numValues != numVariables)
|
||||||
{
|
{
|
||||||
@ -261,7 +261,7 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
|
|||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
expectValidType(variable.type.str(), variable.location);
|
expectValidType(variable.type.str(), variable.location);
|
||||||
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
m_activeVariables.insert(&std::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
||||||
}
|
}
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
return success;
|
return success;
|
||||||
@ -276,7 +276,7 @@ bool AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
|
|||||||
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
||||||
{
|
{
|
||||||
expectValidType(var.type.str(), var.location);
|
expectValidType(var.type.str(), var.location);
|
||||||
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
@ -352,15 +352,15 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
success = false;
|
success = false;
|
||||||
else if (needsLiteralArguments)
|
else if (needsLiteralArguments)
|
||||||
{
|
{
|
||||||
if (arg.type() != typeid(Literal))
|
if (!holds_alternative<Literal>(arg))
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_funCall.functionName.location,
|
_funCall.functionName.location,
|
||||||
"Function expects direct literals as arguments."
|
"Function expects direct literals as arguments."
|
||||||
);
|
);
|
||||||
else if (!m_dataNames.count(boost::get<Literal>(arg).value))
|
else if (!m_dataNames.count(std::get<Literal>(arg).value))
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_funCall.functionName.location,
|
_funCall.functionName.location,
|
||||||
"Unknown data object \"" + boost::get<Literal>(arg).value.str() + "\"."
|
"Unknown data object \"" + std::get<Literal>(arg).value.str() + "\"."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,7 +526,7 @@ bool AsmAnalyzer::operator()(Block const& _block)
|
|||||||
int const initialStackHeight = m_stackHeight;
|
int const initialStackHeight = m_stackHeight;
|
||||||
|
|
||||||
for (auto const& s: _block.statements)
|
for (auto const& s: _block.statements)
|
||||||
if (!boost::apply_visitor(*this, s))
|
if (!std::visit(*this, s))
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
m_stackHeight -= scope(&_block).numberOfVariables();
|
m_stackHeight -= scope(&_block).numberOfVariables();
|
||||||
@ -555,7 +555,7 @@ bool AsmAnalyzer::expectExpression(Expression const& _expr)
|
|||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
int const initialHeight = m_stackHeight;
|
int const initialHeight = m_stackHeight;
|
||||||
if (!boost::apply_visitor(*this, _expr))
|
if (!std::visit(*this, _expr))
|
||||||
success = false;
|
success = false;
|
||||||
if (success && !expectDeposit(1, initialHeight, locationOf(_expr)))
|
if (success && !expectDeposit(1, initialHeight, locationOf(_expr)))
|
||||||
success = false;
|
success = false;
|
||||||
@ -586,12 +586,12 @@ bool AsmAnalyzer::checkAssignment(Identifier const& _variable, size_t _valueSize
|
|||||||
if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
|
if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
|
||||||
{
|
{
|
||||||
// Check that it is a variable
|
// Check that it is a variable
|
||||||
if (var->type() != typeid(Scope::Variable))
|
if (!holds_alternative<Scope::Variable>(*var))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
|
m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if (!m_activeVariables.count(&boost::get<Scope::Variable>(*var)))
|
else if (!m_activeVariables.count(&std::get<Scope::Variable>(*var)))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_variable.location,
|
_variable.location,
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include <libyul/backends/evm/AbstractAssembly.h>
|
#include <libyul/backends/evm/AbstractAssembly.h>
|
||||||
#include <libyul/backends/evm/EVMDialect.h>
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -53,7 +51,7 @@ struct AsmAnalysisInfo;
|
|||||||
* references and performs other checks.
|
* references and performs other checks.
|
||||||
* If all these checks pass, code generation should not throw errors.
|
* If all these checks pass, code generation should not throw errors.
|
||||||
*/
|
*/
|
||||||
class AsmAnalyzer: public boost::static_visitor<bool>
|
class AsmAnalyzer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AsmAnalyzer(
|
explicit AsmAnalyzer(
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -79,7 +78,7 @@ struct Continue { langutil::SourceLocation location; };
|
|||||||
/// Leave statement (valid within function)
|
/// Leave statement (valid within function)
|
||||||
struct Leave { langutil::SourceLocation location; };
|
struct Leave { langutil::SourceLocation location; };
|
||||||
|
|
||||||
struct LocationExtractor: boost::static_visitor<langutil::SourceLocation>
|
struct LocationExtractor
|
||||||
{
|
{
|
||||||
template <class T> langutil::SourceLocation operator()(T const& _node) const
|
template <class T> langutil::SourceLocation operator()(T const& _node) const
|
||||||
{
|
{
|
||||||
@ -90,7 +89,7 @@ struct LocationExtractor: boost::static_visitor<langutil::SourceLocation>
|
|||||||
/// Extracts the source location from an inline assembly node.
|
/// Extracts the source location from an inline assembly node.
|
||||||
template <class T> inline langutil::SourceLocation locationOf(T const& _node)
|
template <class T> inline langutil::SourceLocation locationOf(T const& _node)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(LocationExtractor(), _node);
|
return std::visit(LocationExtractor(), _node);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <variant>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -46,7 +46,7 @@ struct Block;
|
|||||||
|
|
||||||
struct TypedName;
|
struct TypedName;
|
||||||
|
|
||||||
using Expression = boost::variant<FunctionCall, Identifier, Literal>;
|
using Expression = std::variant<FunctionCall, Identifier, Literal>;
|
||||||
using Statement = boost::variant<ExpressionStatement, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Break, Continue, Leave, Block>;
|
using Statement = std::variant<ExpressionStatement, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Break, Continue, Leave, Block>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ Json::Value AsmJsonConverter::operator()(Assignment const& _node) const
|
|||||||
Json::Value ret = createAstNode(_node.location, "YulAssignment");
|
Json::Value ret = createAstNode(_node.location, "YulAssignment");
|
||||||
for (auto const& var: _node.variableNames)
|
for (auto const& var: _node.variableNames)
|
||||||
ret["variableNames"].append((*this)(var));
|
ret["variableNames"].append((*this)(var));
|
||||||
ret["value"] = _node.value ? boost::apply_visitor(*this, *_node.value) : Json::nullValue;
|
ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const
|
|||||||
Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const
|
Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const
|
||||||
{
|
{
|
||||||
Json::Value ret = createAstNode(_node.location, "YulExpressionStatement");
|
Json::Value ret = createAstNode(_node.location, "YulExpressionStatement");
|
||||||
ret["expression"] = boost::apply_visitor(*this, _node.expression);
|
ret["expression"] = std::visit(*this, _node.expression);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const
|
|||||||
for (auto const& var: _node.variables)
|
for (auto const& var: _node.variables)
|
||||||
ret["variables"].append((*this)(var));
|
ret["variables"].append((*this)(var));
|
||||||
|
|
||||||
ret["value"] = _node.value ? boost::apply_visitor(*this, *_node.value) : Json::nullValue;
|
ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ Json::Value AsmJsonConverter::operator()(If const& _node) const
|
|||||||
{
|
{
|
||||||
solAssert(_node.condition, "Invalid if condition.");
|
solAssert(_node.condition, "Invalid if condition.");
|
||||||
Json::Value ret = createAstNode(_node.location, "YulIf");
|
Json::Value ret = createAstNode(_node.location, "YulIf");
|
||||||
ret["condition"] = boost::apply_visitor(*this, *_node.condition);
|
ret["condition"] = std::visit(*this, *_node.condition);
|
||||||
ret["body"] = (*this)(_node.body);
|
ret["body"] = (*this)(_node.body);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ Json::Value AsmJsonConverter::operator()(Switch const& _node) const
|
|||||||
{
|
{
|
||||||
solAssert(_node.expression, "Invalid expression pointer.");
|
solAssert(_node.expression, "Invalid expression pointer.");
|
||||||
Json::Value ret = createAstNode(_node.location, "YulSwitch");
|
Json::Value ret = createAstNode(_node.location, "YulSwitch");
|
||||||
ret["expression"] = boost::apply_visitor(*this, *_node.expression);
|
ret["expression"] = std::visit(*this, *_node.expression);
|
||||||
for (auto const& var: _node.cases)
|
for (auto const& var: _node.cases)
|
||||||
ret["cases"].append((*this)(var));
|
ret["cases"].append((*this)(var));
|
||||||
return ret;
|
return ret;
|
||||||
@ -158,7 +158,7 @@ Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const
|
|||||||
solAssert(_node.condition, "Invalid for loop condition.");
|
solAssert(_node.condition, "Invalid for loop condition.");
|
||||||
Json::Value ret = createAstNode(_node.location, "YulForLoop");
|
Json::Value ret = createAstNode(_node.location, "YulForLoop");
|
||||||
ret["pre"] = (*this)(_node.pre);
|
ret["pre"] = (*this)(_node.pre);
|
||||||
ret["condition"] = boost::apply_visitor(*this, *_node.condition);
|
ret["condition"] = std::visit(*this, *_node.condition);
|
||||||
ret["post"] = (*this)(_node.post);
|
ret["post"] = (*this)(_node.post);
|
||||||
ret["body"] = (*this)(_node.body);
|
ret["body"] = (*this)(_node.body);
|
||||||
return ret;
|
return ret;
|
||||||
@ -195,7 +195,7 @@ Json::Value AsmJsonConverter::vectorOfVariantsToJson(vector<T> const& _vec) cons
|
|||||||
{
|
{
|
||||||
Json::Value ret{Json::arrayValue};
|
Json::Value ret{Json::arrayValue};
|
||||||
for (auto const& var: _vec)
|
for (auto const& var: _vec)
|
||||||
ret.append(boost::apply_visitor(*this, var));
|
ret.append(std::visit(*this, var));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ Statement Parser::parseStatement()
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (elementary.type() != typeid(Identifier))
|
if (!holds_alternative<Identifier>(elementary))
|
||||||
{
|
{
|
||||||
auto const token = currentToken() == Token::Comma ? "," : ":=";
|
auto const token = currentToken() == Token::Comma ? "," : ":=";
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ Statement Parser::parseStatement()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const& identifier = boost::get<Identifier>(elementary);
|
auto const& identifier = std::get<Identifier>(elementary);
|
||||||
|
|
||||||
if (m_dialect.builtin(identifier.name))
|
if (m_dialect.builtin(identifier.name))
|
||||||
fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\".");
|
fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\".");
|
||||||
@ -205,7 +205,7 @@ Statement Parser::parseStatement()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assignment assignment =
|
Assignment assignment =
|
||||||
createWithLocation<Assignment>(boost::get<Identifier>(elementary).location);
|
createWithLocation<Assignment>(std::get<Identifier>(elementary).location);
|
||||||
assignment.variableNames = std::move(variableNames);
|
assignment.variableNames = std::move(variableNames);
|
||||||
|
|
||||||
expectToken(Token::AssemblyAssign);
|
expectToken(Token::AssemblyAssign);
|
||||||
@ -220,14 +220,14 @@ Statement Parser::parseStatement()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementary.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(elementary))
|
||||||
{
|
{
|
||||||
Identifier& identifier = boost::get<Identifier>(elementary);
|
Identifier& identifier = std::get<Identifier>(elementary);
|
||||||
return ExpressionStatement{identifier.location, { move(identifier) }};
|
return ExpressionStatement{identifier.location, { move(identifier) }};
|
||||||
}
|
}
|
||||||
else if (elementary.type() == typeid(Literal))
|
else if (holds_alternative<Literal>(elementary))
|
||||||
{
|
{
|
||||||
Expression expr = boost::get<Literal>(elementary);
|
Expression expr = std::get<Literal>(elementary);
|
||||||
return ExpressionStatement{locationOf(expr), expr};
|
return ExpressionStatement{locationOf(expr), expr};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -247,9 +247,9 @@ Case Parser::parseCase()
|
|||||||
{
|
{
|
||||||
advance();
|
advance();
|
||||||
ElementaryOperation literal = parseElementaryOperation();
|
ElementaryOperation literal = parseElementaryOperation();
|
||||||
if (literal.type() != typeid(Literal))
|
if (!holds_alternative<Literal>(literal))
|
||||||
fatalParserError("Literal expected.");
|
fatalParserError("Literal expected.");
|
||||||
_case.value = make_unique<Literal>(boost::get<Literal>(std::move(literal)));
|
_case.value = make_unique<Literal>(std::get<Literal>(std::move(literal)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "Case or default case expected.");
|
solAssert(false, "Case or default case expected.");
|
||||||
@ -286,14 +286,14 @@ Expression Parser::parseExpression()
|
|||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
|
|
||||||
ElementaryOperation operation = parseElementaryOperation();
|
ElementaryOperation operation = parseElementaryOperation();
|
||||||
if (operation.type() == typeid(FunctionCall) || currentToken() == Token::LParen)
|
if (holds_alternative<FunctionCall>(operation) || currentToken() == Token::LParen)
|
||||||
return parseCall(std::move(operation));
|
return parseCall(std::move(operation));
|
||||||
else if (operation.type() == typeid(Identifier))
|
else if (holds_alternative<Identifier>(operation))
|
||||||
return boost::get<Identifier>(operation);
|
return std::get<Identifier>(operation);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(operation.type() == typeid(Literal), "");
|
solAssert(holds_alternative<Literal>(operation), "");
|
||||||
return boost::get<Literal>(operation);
|
return std::get<Literal>(operation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,13 +464,13 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
|
|||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
|
|
||||||
FunctionCall ret;
|
FunctionCall ret;
|
||||||
if (_initialOp.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_initialOp))
|
||||||
{
|
{
|
||||||
ret.functionName = std::move(boost::get<Identifier>(_initialOp));
|
ret.functionName = std::move(std::get<Identifier>(_initialOp));
|
||||||
ret.location = ret.functionName.location;
|
ret.location = ret.functionName.location;
|
||||||
}
|
}
|
||||||
else if (_initialOp.type() == typeid(FunctionCall))
|
else if (holds_alternative<FunctionCall>(_initialOp))
|
||||||
ret = std::move(boost::get<FunctionCall>(_initialOp));
|
ret = std::move(std::get<FunctionCall>(_initialOp));
|
||||||
else
|
else
|
||||||
fatalParserError(
|
fatalParserError(
|
||||||
m_dialect.flavour == AsmFlavour::Yul ?
|
m_dialect.flavour == AsmFlavour::Yul ?
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
#include <liblangutil/ParserBase.h>
|
#include <liblangutil/ParserBase.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ public:
|
|||||||
static std::map<std::string, dev::eth::Instruction> const& instructions();
|
static std::map<std::string, dev::eth::Instruction> const& instructions();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ElementaryOperation = boost::variant<Instruction, Literal, Identifier, FunctionCall>;
|
using ElementaryOperation = std::variant<Instruction, Literal, Identifier, FunctionCall>;
|
||||||
|
|
||||||
/// Creates an inline assembly node with the given source location.
|
/// Creates an inline assembly node with the given source location.
|
||||||
template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const
|
template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const
|
||||||
|
@ -90,7 +90,7 @@ string AsmPrinter::operator()(Identifier const& _identifier) const
|
|||||||
|
|
||||||
string AsmPrinter::operator()(ExpressionStatement const& _statement) const
|
string AsmPrinter::operator()(ExpressionStatement const& _statement) const
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _statement.expression);
|
return std::visit(*this, _statement.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(Assignment const& _assignment) const
|
string AsmPrinter::operator()(Assignment const& _assignment) const
|
||||||
@ -99,7 +99,7 @@ string AsmPrinter::operator()(Assignment const& _assignment) const
|
|||||||
string variables = (*this)(_assignment.variableNames.front());
|
string variables = (*this)(_assignment.variableNames.front());
|
||||||
for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
|
for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
|
||||||
variables += ", " + (*this)(_assignment.variableNames[i]);
|
variables += ", " + (*this)(_assignment.variableNames[i]);
|
||||||
return variables + " := " + boost::apply_visitor(*this, *_assignment.value);
|
return variables + " := " + std::visit(*this, *_assignment.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const
|
string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const
|
||||||
@ -114,7 +114,7 @@ string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) c
|
|||||||
if (_variableDeclaration.value)
|
if (_variableDeclaration.value)
|
||||||
{
|
{
|
||||||
out += " := ";
|
out += " := ";
|
||||||
out += boost::apply_visitor(*this, *_variableDeclaration.value);
|
out += std::visit(*this, *_variableDeclaration.value);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ string AsmPrinter::operator()(FunctionCall const& _functionCall) const
|
|||||||
return
|
return
|
||||||
(*this)(_functionCall.functionName) + "(" +
|
(*this)(_functionCall.functionName) + "(" +
|
||||||
boost::algorithm::join(
|
boost::algorithm::join(
|
||||||
_functionCall.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)),
|
_functionCall.arguments | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||||
", " ) +
|
", " ) +
|
||||||
")";
|
")";
|
||||||
}
|
}
|
||||||
@ -161,13 +161,13 @@ string AsmPrinter::operator()(If const& _if) const
|
|||||||
char delim = '\n';
|
char delim = '\n';
|
||||||
if (body.find('\n') == string::npos)
|
if (body.find('\n') == string::npos)
|
||||||
delim = ' ';
|
delim = ' ';
|
||||||
return "if " + boost::apply_visitor(*this, *_if.condition) + delim + (*this)(_if.body);
|
return "if " + std::visit(*this, *_if.condition) + delim + (*this)(_if.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(Switch const& _switch) const
|
string AsmPrinter::operator()(Switch const& _switch) const
|
||||||
{
|
{
|
||||||
solAssert(_switch.expression, "Invalid expression pointer.");
|
solAssert(_switch.expression, "Invalid expression pointer.");
|
||||||
string out = "switch " + boost::apply_visitor(*this, *_switch.expression);
|
string out = "switch " + std::visit(*this, *_switch.expression);
|
||||||
for (auto const& _case: _switch.cases)
|
for (auto const& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
if (!_case.value)
|
if (!_case.value)
|
||||||
@ -183,7 +183,7 @@ string AsmPrinter::operator()(ForLoop const& _forLoop) const
|
|||||||
{
|
{
|
||||||
solAssert(_forLoop.condition, "Invalid for loop condition.");
|
solAssert(_forLoop.condition, "Invalid for loop condition.");
|
||||||
string pre = (*this)(_forLoop.pre);
|
string pre = (*this)(_forLoop.pre);
|
||||||
string condition = boost::apply_visitor(*this, *_forLoop.condition);
|
string condition = std::visit(*this, *_forLoop.condition);
|
||||||
string post = (*this)(_forLoop.post);
|
string post = (*this)(_forLoop.post);
|
||||||
char delim = '\n';
|
char delim = '\n';
|
||||||
if (
|
if (
|
||||||
@ -217,7 +217,7 @@ string AsmPrinter::operator()(Block const& _block) const
|
|||||||
if (_block.statements.empty())
|
if (_block.statements.empty())
|
||||||
return "{ }";
|
return "{ }";
|
||||||
string body = boost::algorithm::join(
|
string body = boost::algorithm::join(
|
||||||
_block.statements | boost::adaptors::transformed(boost::apply_visitor(*this)),
|
_block.statements | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||||
"\n"
|
"\n"
|
||||||
);
|
);
|
||||||
if (body.size() < 30 && body.find('\n') == string::npos)
|
if (body.size() < 30 && body.find('\n') == string::npos)
|
||||||
|
@ -26,12 +26,10 @@
|
|||||||
|
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
class AsmPrinter: public boost::static_visitor<std::string>
|
class AsmPrinter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}
|
explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}
|
||||||
|
@ -58,7 +58,7 @@ Scope::Identifier* Scope::lookup(YulString _name)
|
|||||||
auto id = s->identifiers.find(_name);
|
auto id = s->identifiers.find(_name);
|
||||||
if (id != s->identifiers.end())
|
if (id != s->identifiers.end())
|
||||||
{
|
{
|
||||||
if (crossedFunctionBoundary && id->second.type() == typeid(Scope::Variable))
|
if (crossedFunctionBoundary && holds_alternative<Scope::Variable>(id->second))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else
|
else
|
||||||
return &id->second;
|
return &id->second;
|
||||||
@ -84,7 +84,7 @@ size_t Scope::numberOfVariables() const
|
|||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (auto const& identifier: identifiers)
|
for (auto const& identifier: identifiers)
|
||||||
if (identifier.second.type() == typeid(Scope::Variable))
|
if (holds_alternative<Scope::Variable>(identifier.second))
|
||||||
count++;
|
count++;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,10 @@
|
|||||||
|
|
||||||
#include <libdevcore/Visitor.h>
|
#include <libdevcore/Visitor.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
@ -48,7 +47,7 @@ struct Scope
|
|||||||
std::vector<YulType> returns;
|
std::vector<YulType> returns;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Identifier = boost::variant<Variable, Label, Function>;
|
using Identifier = std::variant<Variable, Label, Function>;
|
||||||
using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>;
|
using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>;
|
||||||
using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>;
|
using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>;
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ struct Scope
|
|||||||
{
|
{
|
||||||
if (Identifier* id = lookup(_name))
|
if (Identifier* id = lookup(_name))
|
||||||
{
|
{
|
||||||
boost::apply_visitor(_visitor, *id);
|
std::visit(_visitor, *id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -47,7 +47,7 @@ ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter):
|
|||||||
|
|
||||||
bool ScopeFiller::operator()(ExpressionStatement const& _expr)
|
bool ScopeFiller::operator()(ExpressionStatement const& _expr)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _expr.expression);
|
return std::visit(*this, _expr.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)
|
bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)
|
||||||
@ -102,7 +102,7 @@ bool ScopeFiller::operator()(ForLoop const& _forLoop)
|
|||||||
if (!(*this)(_forLoop.pre))
|
if (!(*this)(_forLoop.pre))
|
||||||
success = false;
|
success = false;
|
||||||
m_currentScope = &scope(&_forLoop.pre);
|
m_currentScope = &scope(&_forLoop.pre);
|
||||||
if (!boost::apply_visitor(*this, *_forLoop.condition))
|
if (!std::visit(*this, *_forLoop.condition))
|
||||||
success = false;
|
success = false;
|
||||||
if (!(*this)(_forLoop.body))
|
if (!(*this)(_forLoop.body))
|
||||||
success = false;
|
success = false;
|
||||||
@ -123,11 +123,11 @@ bool ScopeFiller::operator()(Block const& _block)
|
|||||||
// First visit all functions to make them create
|
// First visit all functions to make them create
|
||||||
// an entry in the scope according to their visibility.
|
// an entry in the scope according to their visibility.
|
||||||
for (auto const& s: _block.statements)
|
for (auto const& s: _block.statements)
|
||||||
if (s.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(s))
|
||||||
if (!registerFunction(boost::get<FunctionDefinition>(s)))
|
if (!registerFunction(std::get<FunctionDefinition>(s)))
|
||||||
success = false;
|
success = false;
|
||||||
for (auto const& s: _block.statements)
|
for (auto const& s: _block.statements)
|
||||||
if (!boost::apply_visitor(*this, s))
|
if (!std::visit(*this, s))
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
m_currentScope = m_currentScope->superScope;
|
m_currentScope = m_currentScope->superScope;
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ struct AsmAnalysisInfo;
|
|||||||
* Fills scopes with identifiers and checks for name clashes.
|
* Fills scopes with identifiers and checks for name clashes.
|
||||||
* Does not resolve references.
|
* Does not resolve references.
|
||||||
*/
|
*/
|
||||||
class ScopeFiller: public boost::static_visitor<bool>
|
class ScopeFiller
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter);
|
ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter);
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
@ -35,13 +37,13 @@ using Representation = ConstantOptimiser::Representation;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct MiniEVMInterpreter: boost::static_visitor<u256>
|
struct MiniEVMInterpreter
|
||||||
{
|
{
|
||||||
explicit MiniEVMInterpreter(EVMDialect const& _dialect): m_dialect(_dialect) {}
|
explicit MiniEVMInterpreter(EVMDialect const& _dialect): m_dialect(_dialect) {}
|
||||||
|
|
||||||
u256 eval(Expression const& _expr)
|
u256 eval(Expression const& _expr)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _expr);
|
return std::visit(*this, _expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 eval(dev::eth::Instruction _instr, vector<Expression> const& _arguments)
|
u256 eval(dev::eth::Instruction _instr, vector<Expression> const& _arguments)
|
||||||
@ -88,9 +90,9 @@ struct MiniEVMInterpreter: boost::static_visitor<u256>
|
|||||||
|
|
||||||
void ConstantOptimiser::visit(Expression& _e)
|
void ConstantOptimiser::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
if (_e.type() == typeid(Literal))
|
if (holds_alternative<Literal>(_e))
|
||||||
{
|
{
|
||||||
Literal const& literal = boost::get<Literal>(_e);
|
Literal const& literal = std::get<Literal>(_e);
|
||||||
if (literal.kind != LiteralKind::Number)
|
if (literal.kind != LiteralKind::Number)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ Expression const* RepresentationFinder::tryFindRepresentation(dev::u256 const& _
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Representation const& repr = findRepresentation(_value);
|
Representation const& repr = findRepresentation(_value);
|
||||||
if (repr.expression->type() == typeid(Literal))
|
if (holds_alternative<Literal>(*repr.expression))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else
|
else
|
||||||
return repr.expression.get();
|
return repr.expression.get();
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
@ -146,9 +148,9 @@ void CodeTransform::freeUnusedVariables()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto const& identifier: m_scope->identifiers)
|
for (auto const& identifier: m_scope->identifiers)
|
||||||
if (identifier.second.type() == typeid(Scope::Variable))
|
if (holds_alternative<Scope::Variable>(identifier.second))
|
||||||
{
|
{
|
||||||
Scope::Variable const& var = boost::get<Scope::Variable>(identifier.second);
|
Scope::Variable const& var = std::get<Scope::Variable>(identifier.second);
|
||||||
if (m_variablesScheduledForDeletion.count(&var))
|
if (m_variablesScheduledForDeletion.count(&var))
|
||||||
deleteVariable(var);
|
deleteVariable(var);
|
||||||
}
|
}
|
||||||
@ -179,7 +181,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, *_varDecl.value);
|
std::visit(*this, *_varDecl.value);
|
||||||
expectDeposit(numVariables, height);
|
expectDeposit(numVariables, height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -193,7 +195,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
|
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
|
||||||
{
|
{
|
||||||
YulString varName = _varDecl.variables[varIndex].name;
|
YulString varName = _varDecl.variables[varIndex].name;
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(varName));
|
auto& var = std::get<Scope::Variable>(m_scope->identifiers.at(varName));
|
||||||
m_context->variableStackHeights[&var] = height + varIndex;
|
m_context->variableStackHeights[&var] = height + varIndex;
|
||||||
if (!m_allowStackOpt)
|
if (!m_allowStackOpt)
|
||||||
continue;
|
continue;
|
||||||
@ -242,7 +244,7 @@ void CodeTransform::stackError(StackTooDeepError _error, int _targetStackHeight)
|
|||||||
void CodeTransform::operator()(Assignment const& _assignment)
|
void CodeTransform::operator()(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
boost::apply_visitor(*this, *_assignment.value);
|
std::visit(*this, *_assignment.value);
|
||||||
expectDeposit(_assignment.variableNames.size(), height);
|
expectDeposit(_assignment.variableNames.size(), height);
|
||||||
|
|
||||||
m_assembly.setSourceLocation(_assignment.location);
|
m_assembly.setSourceLocation(_assignment.location);
|
||||||
@ -253,7 +255,7 @@ void CodeTransform::operator()(Assignment const& _assignment)
|
|||||||
void CodeTransform::operator()(ExpressionStatement const& _statement)
|
void CodeTransform::operator()(ExpressionStatement const& _statement)
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(_statement.location);
|
m_assembly.setSourceLocation(_statement.location);
|
||||||
boost::apply_visitor(*this, _statement.expression);
|
std::visit(*this, _statement.expression);
|
||||||
checkStackHeight(&_statement);
|
checkStackHeight(&_statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +425,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
solAssert(m_scope, "");
|
solAssert(m_scope, "");
|
||||||
solAssert(m_scope->identifiers.count(_function.name), "");
|
solAssert(m_scope->identifiers.count(_function.name), "");
|
||||||
Scope::Function& function = boost::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
Scope::Function& function = std::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
||||||
|
|
||||||
int const localStackAdjustment = m_evm15 ? 0 : 1;
|
int const localStackAdjustment = m_evm15 ? 0 : 1;
|
||||||
int height = localStackAdjustment;
|
int height = localStackAdjustment;
|
||||||
@ -432,7 +434,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
solAssert(varScope, "");
|
solAssert(varScope, "");
|
||||||
for (auto const& v: _function.parameters | boost::adaptors::reversed)
|
for (auto const& v: _function.parameters | boost::adaptors::reversed)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
auto& var = std::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
||||||
m_context->variableStackHeights[&var] = height++;
|
m_context->variableStackHeights[&var] = height++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +452,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
|
|
||||||
for (auto const& v: _function.returnVariables)
|
for (auto const& v: _function.returnVariables)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
auto& var = std::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
||||||
m_context->variableStackHeights[&var] = height++;
|
m_context->variableStackHeights[&var] = height++;
|
||||||
// Preset stack slots for return variables to zero.
|
// Preset stack slots for return variables to zero.
|
||||||
m_assembly.appendConstant(u256(0));
|
m_assembly.appendConstant(u256(0));
|
||||||
@ -681,7 +683,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope:
|
|||||||
void CodeTransform::visitExpression(Expression const& _expression)
|
void CodeTransform::visitExpression(Expression const& _expression)
|
||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
boost::apply_visitor(*this, _expression);
|
std::visit(*this, _expression);
|
||||||
expectDeposit(1, height);
|
expectDeposit(1, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,7 +694,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
|||||||
for (auto const& statement: _statements)
|
for (auto const& statement: _statements)
|
||||||
{
|
{
|
||||||
freeUnusedVariables();
|
freeUnusedVariables();
|
||||||
auto const* functionDefinition = boost::get<FunctionDefinition>(&statement);
|
auto const* functionDefinition = std::get_if<FunctionDefinition>(&statement);
|
||||||
if (functionDefinition && !jumpTarget)
|
if (functionDefinition && !jumpTarget)
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(locationOf(statement));
|
m_assembly.setSourceLocation(locationOf(statement));
|
||||||
@ -705,7 +707,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
|||||||
jumpTarget = std::nullopt;
|
jumpTarget = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::apply_visitor(*this, statement);
|
std::visit(*this, statement);
|
||||||
}
|
}
|
||||||
// we may have a leftover jumpTarget
|
// we may have a leftover jumpTarget
|
||||||
if (jumpTarget)
|
if (jumpTarget)
|
||||||
@ -723,9 +725,9 @@ void CodeTransform::finalizeBlock(Block const& _block, int blockStartStackHeight
|
|||||||
// pop variables
|
// pop variables
|
||||||
solAssert(m_info.scopes.at(&_block).get() == m_scope, "");
|
solAssert(m_info.scopes.at(&_block).get() == m_scope, "");
|
||||||
for (auto const& id: m_scope->identifiers)
|
for (auto const& id: m_scope->identifiers)
|
||||||
if (id.second.type() == typeid(Scope::Variable))
|
if (holds_alternative<Scope::Variable>(id.second))
|
||||||
{
|
{
|
||||||
Scope::Variable const& var = boost::get<Scope::Variable>(id.second);
|
Scope::Variable const& var = std::get<Scope::Variable>(id.second);
|
||||||
if (m_allowStackOpt)
|
if (m_allowStackOpt)
|
||||||
{
|
{
|
||||||
solAssert(!m_context->variableStackHeights.count(&var), "");
|
solAssert(!m_context->variableStackHeights.count(&var), "");
|
||||||
@ -753,7 +755,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
solAssert(m_scope, "");
|
solAssert(m_scope, "");
|
||||||
if (auto var = m_scope->lookup(_variableName.name))
|
if (auto var = m_scope->lookup(_variableName.name))
|
||||||
{
|
{
|
||||||
Scope::Variable const& _var = boost::get<Scope::Variable>(*var);
|
Scope::Variable const& _var = std::get<Scope::Variable>(*var);
|
||||||
if (int heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
if (int heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
||||||
m_assembly.appendInstruction(dev::eth::swapInstruction(heightDiff - 1));
|
m_assembly.appendInstruction(dev::eth::swapInstruction(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(dev::eth::Instruction::POP);
|
m_assembly.appendInstruction(dev::eth::Instruction::POP);
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
#include <libyul/AsmScope.h>
|
#include <libyul/AsmScope.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
@ -108,7 +106,7 @@ private:
|
|||||||
Scope* m_scope = nullptr;
|
Scope* m_scope = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CodeTransform: public boost::static_visitor<>
|
class CodeTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Create the code transformer.
|
/// Create the code transformer.
|
||||||
|
@ -113,7 +113,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
yulAssert(_context.currentObject, "No object available.");
|
yulAssert(_context.currentObject, "No object available.");
|
||||||
yulAssert(_call.arguments.size() == 1, "");
|
yulAssert(_call.arguments.size() == 1, "");
|
||||||
Expression const& arg = _call.arguments.front();
|
Expression const& arg = _call.arguments.front();
|
||||||
YulString dataName = boost::get<Literal>(arg).value;
|
YulString dataName = std::get<Literal>(arg).value;
|
||||||
if (_context.currentObject->name == dataName)
|
if (_context.currentObject->name == dataName)
|
||||||
_assembly.appendAssemblySize();
|
_assembly.appendAssemblySize();
|
||||||
else
|
else
|
||||||
@ -134,7 +134,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
yulAssert(_context.currentObject, "No object available.");
|
yulAssert(_context.currentObject, "No object available.");
|
||||||
yulAssert(_call.arguments.size() == 1, "");
|
yulAssert(_call.arguments.size() == 1, "");
|
||||||
Expression const& arg = _call.arguments.front();
|
Expression const& arg = _call.arguments.front();
|
||||||
YulString dataName = boost::get<Literal>(arg).value;
|
YulString dataName = std::get<Literal>(arg).value;
|
||||||
if (_context.currentObject->name == dataName)
|
if (_context.currentObject->name == dataName)
|
||||||
_assembly.appendConstant(0);
|
_assembly.appendConstant(0);
|
||||||
else
|
else
|
||||||
|
@ -90,7 +90,7 @@ void GasMeterVisitor::operator()(Literal const& _lit)
|
|||||||
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1);
|
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1);
|
||||||
m_dataGas +=
|
m_dataGas +=
|
||||||
singleByteDataGas() +
|
singleByteDataGas() +
|
||||||
size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation));
|
size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation, m_dialect.evmVersion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GasMeterVisitor::operator()(Identifier const&)
|
void GasMeterVisitor::operator()(Identifier const&)
|
||||||
@ -102,7 +102,7 @@ void GasMeterVisitor::operator()(Identifier const&)
|
|||||||
size_t GasMeterVisitor::singleByteDataGas() const
|
size_t GasMeterVisitor::singleByteDataGas() const
|
||||||
{
|
{
|
||||||
if (m_isCreation)
|
if (m_isCreation)
|
||||||
return dev::eth::GasCosts::txDataNonZeroGas;
|
return dev::eth::GasCosts::txDataNonZeroGas(m_dialect.evmVersion());
|
||||||
else
|
else
|
||||||
return dev::eth::GasCosts::createDataGas;
|
return dev::eth::GasCosts::createDataGas;
|
||||||
}
|
}
|
||||||
|
@ -298,12 +298,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
|||||||
// they are references to object names that should not end up in the code.
|
// they are references to object names that should not end up in the code.
|
||||||
if (_call.functionName == "dataoffset")
|
if (_call.functionName == "dataoffset")
|
||||||
{
|
{
|
||||||
string name = boost::get<StringLiteral>(_call.arguments.at(0)).value;
|
string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
|
||||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
|
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
|
||||||
}
|
}
|
||||||
else if (_call.functionName == "datasize")
|
else if (_call.functionName == "datasize")
|
||||||
{
|
{
|
||||||
string name = boost::get<StringLiteral>(_call.arguments.at(0)).value;
|
string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
|
||||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
|
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ bytes BinaryTransform::operator()(FunctionCall const& _call)
|
|||||||
bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
|
bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
boost::apply_visitor(*this, *_assignment.value) +
|
std::visit(*this, *_assignment.value) +
|
||||||
toBytes(Opcode::LocalSet) +
|
toBytes(Opcode::LocalSet) +
|
||||||
lebEncode(m_locals.at(_assignment.variableName));
|
lebEncode(m_locals.at(_assignment.variableName));
|
||||||
}
|
}
|
||||||
@ -341,7 +341,7 @@ bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
|
|||||||
bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
|
bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
boost::apply_visitor(*this, *_assignment.value) +
|
std::visit(*this, *_assignment.value) +
|
||||||
toBytes(Opcode::GlobalSet) +
|
toBytes(Opcode::GlobalSet) +
|
||||||
lebEncode(m_globals.at(_assignment.variableName));
|
lebEncode(m_globals.at(_assignment.variableName));
|
||||||
}
|
}
|
||||||
@ -349,7 +349,7 @@ bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
|
|||||||
bytes BinaryTransform::operator()(If const& _if)
|
bytes BinaryTransform::operator()(If const& _if)
|
||||||
{
|
{
|
||||||
bytes result =
|
bytes result =
|
||||||
boost::apply_visitor(*this, *_if.condition) +
|
std::visit(*this, *_if.condition) +
|
||||||
toBytes(Opcode::If) +
|
toBytes(Opcode::If) +
|
||||||
toBytes(ValueType::Void);
|
toBytes(ValueType::Void);
|
||||||
|
|
||||||
@ -564,7 +564,7 @@ bytes BinaryTransform::visit(vector<Expression> const& _expressions)
|
|||||||
{
|
{
|
||||||
bytes result;
|
bytes result;
|
||||||
for (auto const& expr: _expressions)
|
for (auto const& expr: _expressions)
|
||||||
result += boost::apply_visitor(*this, expr);
|
result += std::visit(*this, expr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +572,7 @@ bytes BinaryTransform::visitReversed(vector<Expression> const& _expressions)
|
|||||||
{
|
{
|
||||||
bytes result;
|
bytes result;
|
||||||
for (auto const& expr: _expressions | boost::adaptors::reversed)
|
for (auto const& expr: _expressions | boost::adaptors::reversed)
|
||||||
result += boost::apply_visitor(*this, expr);
|
result += std::visit(*this, expr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace wasm
|
|||||||
/**
|
/**
|
||||||
* Web assembly to binary transform.
|
* Web assembly to binary transform.
|
||||||
*/
|
*/
|
||||||
class BinaryTransform: public boost::static_visitor<dev::bytes>
|
class BinaryTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static dev::bytes run(Module const& _module);
|
static dev::bytes run(Module const& _module);
|
||||||
|
@ -694,7 +694,7 @@ Object EVMToEWasmTranslator::run(Object const& _object)
|
|||||||
if (!m_polyfill)
|
if (!m_polyfill)
|
||||||
parsePolyfill();
|
parsePolyfill();
|
||||||
|
|
||||||
Block ast = boost::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code));
|
Block ast = std::get<Block>(Disambiguator(m_dialect, *_object.analysisInfo)(*_object.code));
|
||||||
set<YulString> reservedIdentifiers;
|
set<YulString> reservedIdentifiers;
|
||||||
NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers};
|
NameDispenser nameDispenser{m_dialect, ast, reservedIdentifiers};
|
||||||
OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers};
|
OptimiserStepContext context{m_dialect, nameDispenser, reservedIdentifiers};
|
||||||
@ -752,6 +752,6 @@ void EVMToEWasmTranslator::parsePolyfill()
|
|||||||
|
|
||||||
m_polyfillFunctions.clear();
|
m_polyfillFunctions.clear();
|
||||||
for (auto const& statement: m_polyfill->statements)
|
for (auto const& statement: m_polyfill->statements)
|
||||||
m_polyfillFunctions.insert(boost::get<FunctionDefinition>(statement).name);
|
m_polyfillFunctions.insert(std::get<FunctionDefinition>(statement).name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <variant>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -45,7 +45,7 @@ struct Loop;
|
|||||||
struct Break;
|
struct Break;
|
||||||
struct BreakIf;
|
struct BreakIf;
|
||||||
struct Return;
|
struct Return;
|
||||||
using Expression = boost::variant<
|
using Expression = std::variant<
|
||||||
Literal, StringLiteral, LocalVariable, GlobalVariable,
|
Literal, StringLiteral, LocalVariable, GlobalVariable,
|
||||||
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
||||||
Block, If, Loop, Break, BreakIf, Return
|
Block, If, Loop, Break, BreakIf, Return
|
||||||
|
@ -45,11 +45,11 @@ wasm::Module EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const&
|
|||||||
for (auto const& statement: _ast.statements)
|
for (auto const& statement: _ast.statements)
|
||||||
{
|
{
|
||||||
yulAssert(
|
yulAssert(
|
||||||
statement.type() == typeid(yul::FunctionDefinition),
|
holds_alternative<yul::FunctionDefinition>(statement),
|
||||||
"Expected only function definitions at the highest level."
|
"Expected only function definitions at the highest level."
|
||||||
);
|
);
|
||||||
if (statement.type() == typeid(yul::FunctionDefinition))
|
if (holds_alternative<yul::FunctionDefinition>(statement))
|
||||||
module.functions.emplace_back(transform.translateFunction(boost::get<yul::FunctionDefinition>(statement)));
|
module.functions.emplace_back(transform.translateFunction(std::get<yul::FunctionDefinition>(statement)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& imp: transform.m_functionsToImport)
|
for (auto& imp: transform.m_functionsToImport)
|
||||||
@ -139,7 +139,7 @@ wasm::Expression EWasmCodeTransform::operator()(FunctionCall const& _call)
|
|||||||
{
|
{
|
||||||
vector<wasm::Expression> literals;
|
vector<wasm::Expression> literals;
|
||||||
for (auto const& arg: _call.arguments)
|
for (auto const& arg: _call.arguments)
|
||||||
literals.emplace_back(wasm::StringLiteral{boost::get<Literal>(arg).value.str()});
|
literals.emplace_back(wasm::StringLiteral{std::get<Literal>(arg).value.str()});
|
||||||
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)};
|
return wasm::BuiltinCall{_call.functionName.name.str(), std::move(literals)};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -284,12 +284,12 @@ wasm::Expression EWasmCodeTransform::operator()(Block const& _block)
|
|||||||
|
|
||||||
unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression)
|
unique_ptr<wasm::Expression> EWasmCodeTransform::visit(yul::Expression const& _expression)
|
||||||
{
|
{
|
||||||
return make_unique<wasm::Expression>(boost::apply_visitor(*this, _expression));
|
return make_unique<wasm::Expression>(std::visit(*this, _expression));
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
|
wasm::Expression EWasmCodeTransform::visitReturnByValue(yul::Expression const& _expression)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _expression);
|
return std::visit(*this, _expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
|
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const& _expressions)
|
||||||
@ -302,7 +302,7 @@ vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Expression> const
|
|||||||
|
|
||||||
wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement)
|
wasm::Expression EWasmCodeTransform::visit(yul::Statement const& _statement)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _statement);
|
return std::visit(*this, _statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements)
|
vector<wasm::Expression> EWasmCodeTransform::visit(vector<yul::Statement> const& _statements)
|
||||||
|
@ -32,7 +32,7 @@ namespace yul
|
|||||||
{
|
{
|
||||||
struct AsmAnalysisInfo;
|
struct AsmAnalysisInfo;
|
||||||
|
|
||||||
class EWasmCodeTransform: public boost::static_visitor<wasm::Expression>
|
class EWasmCodeTransform
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast);
|
static wasm::Module run(Dialect const& _dialect, yul::Block const& _ast);
|
||||||
|
@ -176,7 +176,7 @@ string EWasmToText::transform(wasm::FunctionDefinition const& _function)
|
|||||||
|
|
||||||
string EWasmToText::visit(wasm::Expression const& _expression)
|
string EWasmToText::visit(wasm::Expression const& _expression)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(*this, _expression);
|
return std::visit(*this, _expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
string EWasmToText::joinTransformed(vector<wasm::Expression> const& _expressions, char _separator)
|
string EWasmToText::joinTransformed(vector<wasm::Expression> const& _expressions, char _separator)
|
||||||
|
@ -28,7 +28,7 @@ namespace yul
|
|||||||
{
|
{
|
||||||
struct AsmAnalysisInfo;
|
struct AsmAnalysisInfo;
|
||||||
|
|
||||||
class EWasmToText: public boost::static_visitor<std::string>
|
class EWasmToText
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string run(wasm::Module const& _module);
|
std::string run(wasm::Module const& _module);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
@ -79,13 +80,13 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[&](Statement& _s) -> std::optional<vector<Statement>>
|
[&](Statement& _s) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
if (_s.type() == typeid(VariableDeclaration))
|
if (holds_alternative<VariableDeclaration>(_s))
|
||||||
{
|
{
|
||||||
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s);
|
VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
|
||||||
|
|
||||||
// Special handling for datasize and dataoffset - they will only need one variable.
|
// Special handling for datasize and dataoffset - they will only need one variable.
|
||||||
if (varDecl.value && varDecl.value->type() == typeid(FunctionCall))
|
if (varDecl.value && holds_alternative<FunctionCall>(*varDecl.value))
|
||||||
if (BuiltinFunction const* f = m_inputDialect.builtin(boost::get<FunctionCall>(*varDecl.value).functionName.name))
|
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*varDecl.value).functionName.name))
|
||||||
if (f->literalArguments)
|
if (f->literalArguments)
|
||||||
{
|
{
|
||||||
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
|
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
|
||||||
@ -106,7 +107,9 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
return {std::move(ret)};
|
return {std::move(ret)};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!varDecl.value || varDecl.value->type() == typeid(FunctionCall)
|
if (
|
||||||
|
!varDecl.value ||
|
||||||
|
holds_alternative<FunctionCall>(*varDecl.value)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (varDecl.value) visit(*varDecl.value);
|
if (varDecl.value) visit(*varDecl.value);
|
||||||
@ -114,8 +117,8 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
varDecl.value->type() == typeid(Identifier) ||
|
holds_alternative<Identifier>(*varDecl.value) ||
|
||||||
varDecl.value->type() == typeid(Literal)
|
holds_alternative<Literal>(*varDecl.value)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
yulAssert(varDecl.variables.size() == 1, "");
|
yulAssert(varDecl.variables.size() == 1, "");
|
||||||
@ -135,14 +138,14 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
else
|
else
|
||||||
yulAssert(false, "");
|
yulAssert(false, "");
|
||||||
}
|
}
|
||||||
else if (_s.type() == typeid(Assignment))
|
else if (holds_alternative<Assignment>(_s))
|
||||||
{
|
{
|
||||||
Assignment& assignment = boost::get<Assignment>(_s);
|
Assignment& assignment = std::get<Assignment>(_s);
|
||||||
yulAssert(assignment.value, "");
|
yulAssert(assignment.value, "");
|
||||||
|
|
||||||
// Special handling for datasize and dataoffset - they will only need one variable.
|
// Special handling for datasize and dataoffset - they will only need one variable.
|
||||||
if (assignment.value->type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(*assignment.value))
|
||||||
if (BuiltinFunction const* f = m_inputDialect.builtin(boost::get<FunctionCall>(*assignment.value).functionName.name))
|
if (BuiltinFunction const* f = m_inputDialect.builtin(std::get<FunctionCall>(*assignment.value).functionName.name))
|
||||||
if (f->literalArguments)
|
if (f->literalArguments)
|
||||||
{
|
{
|
||||||
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
|
yulAssert(f->name == "datasize"_yulstring || f->name == "dataoffset"_yulstring, "");
|
||||||
@ -163,15 +166,15 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
return {std::move(ret)};
|
return {std::move(ret)};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assignment.value->type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(*assignment.value))
|
||||||
{
|
{
|
||||||
if (assignment.value) visit(*assignment.value);
|
if (assignment.value) visit(*assignment.value);
|
||||||
rewriteIdentifierList(assignment.variableNames);
|
rewriteIdentifierList(assignment.variableNames);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
assignment.value->type() == typeid(Identifier) ||
|
holds_alternative<Identifier>(*assignment.value) ||
|
||||||
assignment.value->type() == typeid(Literal)
|
holds_alternative<Literal>(*assignment.value)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
yulAssert(assignment.variableNames.size() == 1, "");
|
yulAssert(assignment.variableNames.size() == 1, "");
|
||||||
@ -191,8 +194,8 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
else
|
else
|
||||||
yulAssert(false, "");
|
yulAssert(false, "");
|
||||||
}
|
}
|
||||||
else if (_s.type() == typeid(Switch))
|
else if (holds_alternative<Switch>(_s))
|
||||||
return handleSwitch(boost::get<Switch>(_s));
|
return handleSwitch(std::get<Switch>(_s));
|
||||||
else
|
else
|
||||||
visit(_s);
|
visit(_s);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -331,7 +334,7 @@ std::vector<Statement> WordSizeTransform::handleSwitch(Switch& _switch)
|
|||||||
}
|
}
|
||||||
vector<YulString> splitExpressions;
|
vector<YulString> splitExpressions;
|
||||||
for (auto const& expr: expandValue(*_switch.expression))
|
for (auto const& expr: expandValue(*_switch.expression))
|
||||||
splitExpressions.emplace_back(boost::get<Identifier>(*expr).name);
|
splitExpressions.emplace_back(std::get<Identifier>(*expr).name);
|
||||||
|
|
||||||
ret += handleSwitchInternal(
|
ret += handleSwitchInternal(
|
||||||
_switch.location,
|
_switch.location,
|
||||||
@ -361,15 +364,15 @@ array<YulString, 4> WordSizeTransform::generateU64IdentifierNames(YulString cons
|
|||||||
array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const& _e)
|
array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const& _e)
|
||||||
{
|
{
|
||||||
array<unique_ptr<Expression>, 4> ret;
|
array<unique_ptr<Expression>, 4> ret;
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier const& id = boost::get<Identifier>(_e);
|
Identifier const& id = std::get<Identifier>(_e);
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
|
ret[i] = make_unique<Expression>(Identifier{id.location, m_variableMapping.at(id.name)[i]});
|
||||||
}
|
}
|
||||||
else if (_e.type() == typeid(Literal))
|
else if (holds_alternative<Literal>(_e))
|
||||||
{
|
{
|
||||||
Literal const& lit = boost::get<Literal>(_e);
|
Literal const& lit = std::get<Literal>(_e);
|
||||||
u256 val = valueOfLiteral(lit);
|
u256 val = valueOfLiteral(lit);
|
||||||
for (int i = 3; i >= 0; i--)
|
for (int i = 3; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
@ -133,12 +133,12 @@ Statement ASTCopier::operator ()(Block const& _block)
|
|||||||
|
|
||||||
Expression ASTCopier::translate(Expression const& _expression)
|
Expression ASTCopier::translate(Expression const& _expression)
|
||||||
{
|
{
|
||||||
return _expression.apply_visitor(static_cast<ExpressionCopier&>(*this));
|
return std::visit(static_cast<ExpressionCopier&>(*this), _expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement ASTCopier::translate(Statement const& _statement)
|
Statement ASTCopier::translate(Statement const& _statement)
|
||||||
{
|
{
|
||||||
return _statement.apply_visitor(static_cast<StatementCopier&>(*this));
|
return std::visit(static_cast<StatementCopier&>(*this), _statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block ASTCopier::translate(Block const& _block)
|
Block ASTCopier::translate(Block const& _block)
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
|
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -34,7 +32,7 @@
|
|||||||
namespace yul
|
namespace yul
|
||||||
{
|
{
|
||||||
|
|
||||||
class ExpressionCopier: public boost::static_visitor<Expression>
|
class ExpressionCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ExpressionCopier() = default;
|
virtual ~ExpressionCopier() = default;
|
||||||
@ -43,7 +41,7 @@ public:
|
|||||||
virtual Expression operator()(FunctionCall const&) = 0;
|
virtual Expression operator()(FunctionCall const&) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StatementCopier: public boost::static_visitor<Statement>
|
class StatementCopier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~StatementCopier() = default;
|
virtual ~StatementCopier() = default;
|
||||||
|
@ -89,12 +89,12 @@ void ASTWalker::operator()(Block const& _block)
|
|||||||
|
|
||||||
void ASTWalker::visit(Statement const& _st)
|
void ASTWalker::visit(Statement const& _st)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _st);
|
std::visit(*this, _st);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTWalker::visit(Expression const& _e)
|
void ASTWalker::visit(Expression const& _e)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _e);
|
std::visit(*this, _e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTModifier::operator()(FunctionCall& _funCall)
|
void ASTModifier::operator()(FunctionCall& _funCall)
|
||||||
@ -170,10 +170,10 @@ void ASTModifier::operator()(Block& _block)
|
|||||||
|
|
||||||
void ASTModifier::visit(Statement& _st)
|
void ASTModifier::visit(Statement& _st)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _st);
|
std::visit(*this, _st);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTModifier::visit(Expression& _e)
|
void ASTModifier::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, _e);
|
std::visit(*this, _e);
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libyul/YulString.h>
|
#include <libyul/YulString.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -38,7 +36,7 @@ namespace yul
|
|||||||
/**
|
/**
|
||||||
* Generic AST walker.
|
* Generic AST walker.
|
||||||
*/
|
*/
|
||||||
class ASTWalker: public boost::static_visitor<>
|
class ASTWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ASTWalker() = default;
|
virtual ~ASTWalker() = default;
|
||||||
@ -72,7 +70,7 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* Generic AST modifier (i.e. non-const version of ASTWalker).
|
* Generic AST modifier (i.e. non-const version of ASTWalker).
|
||||||
*/
|
*/
|
||||||
class ASTModifier: public boost::static_visitor<>
|
class ASTModifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ASTModifier() = default;
|
virtual ~ASTModifier() = default;
|
||||||
|
@ -32,8 +32,8 @@ void BlockFlattener::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[](Statement& _s) -> std::optional<vector<Statement>>
|
[](Statement& _s) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
if (_s.type() == typeid(Block))
|
if (holds_alternative<Block>(_s))
|
||||||
return std::move(boost::get<Block>(_s).statements);
|
return std::move(std::get<Block>(_s).statements);
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
|||||||
bool descend = true;
|
bool descend = true;
|
||||||
// If this is a function call to a function that requires literal arguments,
|
// If this is a function call to a function that requires literal arguments,
|
||||||
// do not try to simplify there.
|
// do not try to simplify there.
|
||||||
if (_e.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_e))
|
||||||
if (BuiltinFunction const* builtin = m_dialect.builtin(boost::get<FunctionCall>(_e).functionName.name))
|
if (BuiltinFunction const* builtin = m_dialect.builtin(std::get<FunctionCall>(_e).functionName.name))
|
||||||
if (builtin->literalArguments)
|
if (builtin->literalArguments)
|
||||||
// We should not modify function arguments that have to be literals
|
// We should not modify function arguments that have to be literals
|
||||||
// Note that replacing the function call entirely is fine,
|
// Note that replacing the function call entirely is fine,
|
||||||
@ -72,16 +72,16 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
|||||||
if (descend)
|
if (descend)
|
||||||
DataFlowAnalyzer::visit(_e);
|
DataFlowAnalyzer::visit(_e);
|
||||||
|
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier& identifier = boost::get<Identifier>(_e);
|
Identifier& identifier = std::get<Identifier>(_e);
|
||||||
YulString 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 (holds_alternative<Identifier>(*m_value.at(name)))
|
||||||
{
|
{
|
||||||
YulString value = boost::get<Identifier>(*m_value.at(name)).name;
|
YulString value = std::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};
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,12 @@ using namespace yul;
|
|||||||
void ConditionalSimplifier::operator()(Switch& _switch)
|
void ConditionalSimplifier::operator()(Switch& _switch)
|
||||||
{
|
{
|
||||||
visit(*_switch.expression);
|
visit(*_switch.expression);
|
||||||
if (_switch.expression->type() != typeid(Identifier))
|
if (!holds_alternative<Identifier>(*_switch.expression))
|
||||||
{
|
{
|
||||||
ASTModifier::operator()(_switch);
|
ASTModifier::operator()(_switch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
YulString expr = boost::get<Identifier>(*_switch.expression).name;
|
YulString expr = std::get<Identifier>(*_switch.expression).name;
|
||||||
for (auto& _case: _switch.cases)
|
for (auto& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
if (_case.value)
|
if (_case.value)
|
||||||
@ -59,17 +59,17 @@ void ConditionalSimplifier::operator()(Block& _block)
|
|||||||
[&](Statement& _s) -> std::optional<vector<Statement>>
|
[&](Statement& _s) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
visit(_s);
|
visit(_s);
|
||||||
if (_s.type() == typeid(If))
|
if (holds_alternative<If>(_s))
|
||||||
{
|
{
|
||||||
If& _if = boost::get<If>(_s);
|
If& _if = std::get<If>(_s);
|
||||||
if (
|
if (
|
||||||
_if.condition->type() == typeid(Identifier) &&
|
holds_alternative<Identifier>(*_if.condition) &&
|
||||||
!_if.body.statements.empty() &&
|
!_if.body.statements.empty() &&
|
||||||
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
|
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
|
||||||
TerminationFinder::ControlFlow::FlowOut
|
TerminationFinder::ControlFlow::FlowOut
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
YulString condition = boost::get<Identifier>(*_if.condition).name;
|
YulString condition = std::get<Identifier>(*_if.condition).name;
|
||||||
langutil::SourceLocation location = _if.location;
|
langutil::SourceLocation location = _if.location;
|
||||||
return make_vector<Statement>(
|
return make_vector<Statement>(
|
||||||
std::move(_s),
|
std::move(_s),
|
||||||
|
@ -29,12 +29,12 @@ using namespace yul;
|
|||||||
void ConditionalUnsimplifier::operator()(Switch& _switch)
|
void ConditionalUnsimplifier::operator()(Switch& _switch)
|
||||||
{
|
{
|
||||||
visit(*_switch.expression);
|
visit(*_switch.expression);
|
||||||
if (_switch.expression->type() != typeid(Identifier))
|
if (!holds_alternative<Identifier>(*_switch.expression))
|
||||||
{
|
{
|
||||||
ASTModifier::operator()(_switch);
|
ASTModifier::operator()(_switch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
YulString expr = boost::get<Identifier>(*_switch.expression).name;
|
YulString expr = std::get<Identifier>(*_switch.expression).name;
|
||||||
for (auto& _case: _switch.cases)
|
for (auto& _case: _switch.cases)
|
||||||
{
|
{
|
||||||
if (_case.value)
|
if (_case.value)
|
||||||
@ -42,15 +42,15 @@ void ConditionalUnsimplifier::operator()(Switch& _switch)
|
|||||||
(*this)(*_case.value);
|
(*this)(*_case.value);
|
||||||
if (
|
if (
|
||||||
!_case.body.statements.empty() &&
|
!_case.body.statements.empty() &&
|
||||||
_case.body.statements.front().type() == typeid(Assignment)
|
holds_alternative<Assignment>(_case.body.statements.front())
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Assignment const& assignment = boost::get<Assignment>(_case.body.statements.front());
|
Assignment const& assignment = std::get<Assignment>(_case.body.statements.front());
|
||||||
if (
|
if (
|
||||||
assignment.variableNames.size() == 1 &&
|
assignment.variableNames.size() == 1 &&
|
||||||
assignment.variableNames.front().name == expr &&
|
assignment.variableNames.front().name == expr &&
|
||||||
assignment.value->type() == typeid(Literal) &&
|
holds_alternative<Literal>(*assignment.value) &&
|
||||||
valueOfLiteral(boost::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value)
|
valueOfLiteral(std::get<Literal>(*assignment.value)) == valueOfLiteral(*_case.value)
|
||||||
)
|
)
|
||||||
_case.body.statements.erase(_case.body.statements.begin());
|
_case.body.statements.erase(_case.body.statements.begin());
|
||||||
}
|
}
|
||||||
@ -66,27 +66,27 @@ void ConditionalUnsimplifier::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
|
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
if (_stmt1.type() == typeid(If))
|
if (holds_alternative<If>(_stmt1))
|
||||||
{
|
{
|
||||||
If& _if = boost::get<If>(_stmt1);
|
If& _if = std::get<If>(_stmt1);
|
||||||
if (
|
if (
|
||||||
_if.condition->type() == typeid(Identifier) &&
|
holds_alternative<Identifier>(*_if.condition) &&
|
||||||
!_if.body.statements.empty()
|
!_if.body.statements.empty()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
YulString condition = boost::get<Identifier>(*_if.condition).name;
|
YulString condition = std::get<Identifier>(*_if.condition).name;
|
||||||
if (
|
if (
|
||||||
_stmt2.type() == typeid(Assignment) &&
|
holds_alternative<Assignment>(_stmt2) &&
|
||||||
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
|
TerminationFinder(m_dialect).controlFlowKind(_if.body.statements.back()) !=
|
||||||
TerminationFinder::ControlFlow::FlowOut
|
TerminationFinder::ControlFlow::FlowOut
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Assignment const& assignment = boost::get<Assignment>(_stmt2);
|
Assignment const& assignment = std::get<Assignment>(_stmt2);
|
||||||
if (
|
if (
|
||||||
assignment.variableNames.size() == 1 &&
|
assignment.variableNames.size() == 1 &&
|
||||||
assignment.variableNames.front().name == condition &&
|
assignment.variableNames.front().name == condition &&
|
||||||
assignment.value->type() == typeid(Literal) &&
|
holds_alternative<Literal>(*assignment.value) &&
|
||||||
valueOfLiteral(boost::get<Literal>(*assignment.value)) == 0
|
valueOfLiteral(std::get<Literal>(*assignment.value)) == 0
|
||||||
)
|
)
|
||||||
return {make_vector<Statement>(std::move(_stmt1))};
|
return {make_vector<Statement>(std::move(_stmt1))};
|
||||||
}
|
}
|
||||||
|
@ -139,15 +139,15 @@ void ControlFlowSimplifier::operator()(Block& _block)
|
|||||||
void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef)
|
void ControlFlowSimplifier::operator()(FunctionDefinition& _funDef)
|
||||||
{
|
{
|
||||||
ASTModifier::operator()(_funDef);
|
ASTModifier::operator()(_funDef);
|
||||||
if (!_funDef.body.statements.empty() && _funDef.body.statements.back().type() == typeid(Leave))
|
if (!_funDef.body.statements.empty() && holds_alternative<Leave>(_funDef.body.statements.back()))
|
||||||
_funDef.body.statements.pop_back();
|
_funDef.body.statements.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlFlowSimplifier::visit(Statement& _st)
|
void ControlFlowSimplifier::visit(Statement& _st)
|
||||||
{
|
{
|
||||||
if (_st.type() == typeid(ForLoop))
|
if (holds_alternative<ForLoop>(_st))
|
||||||
{
|
{
|
||||||
ForLoop& forLoop = boost::get<ForLoop>(_st);
|
ForLoop& forLoop = std::get<ForLoop>(_st);
|
||||||
yulAssert(forLoop.pre.statements.empty(), "");
|
yulAssert(forLoop.pre.statements.empty(), "");
|
||||||
|
|
||||||
size_t outerBreak = m_numBreakStatements;
|
size_t outerBreak = m_numBreakStatements;
|
||||||
@ -221,7 +221,7 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
|
|||||||
_statements,
|
_statements,
|
||||||
[&](Statement& _stmt) -> OptionalStatements
|
[&](Statement& _stmt) -> OptionalStatements
|
||||||
{
|
{
|
||||||
OptionalStatements result = boost::apply_visitor(visitor, _stmt);
|
OptionalStatements result = std::visit(visitor, _stmt);
|
||||||
if (result)
|
if (result)
|
||||||
simplify(*result);
|
simplify(*result);
|
||||||
else
|
else
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
#include <boost/range/algorithm_ext/erase.hpp>
|
#include <boost/range/algorithm_ext/erase.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
@ -368,19 +369,19 @@ std::optional<pair<YulString, YulString>> DataFlowAnalyzer::isSimpleStore(
|
|||||||
_store == dev::eth::Instruction::SSTORE,
|
_store == dev::eth::Instruction::SSTORE,
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
if (_statement.expression.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_statement.expression))
|
||||||
{
|
{
|
||||||
FunctionCall const& funCall = boost::get<FunctionCall>(_statement.expression);
|
FunctionCall const& funCall = std::get<FunctionCall>(_statement.expression);
|
||||||
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
|
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
|
||||||
if (auto const* builtin = dialect->builtin(funCall.functionName.name))
|
if (auto const* builtin = dialect->builtin(funCall.functionName.name))
|
||||||
if (builtin->instruction == _store)
|
if (builtin->instruction == _store)
|
||||||
if (
|
if (
|
||||||
funCall.arguments.at(0).type() == typeid(Identifier) &&
|
holds_alternative<Identifier>(funCall.arguments.at(0)) &&
|
||||||
funCall.arguments.at(1).type() == typeid(Identifier)
|
holds_alternative<Identifier>(funCall.arguments.at(1))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
YulString key = boost::get<Identifier>(funCall.arguments.at(0)).name;
|
YulString key = std::get<Identifier>(funCall.arguments.at(0)).name;
|
||||||
YulString value = boost::get<Identifier>(funCall.arguments.at(1)).name;
|
YulString value = std::get<Identifier>(funCall.arguments.at(1)).name;
|
||||||
return make_pair(key, value);
|
return make_pair(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ void DeadCodeEliminator::operator()(Block& _block)
|
|||||||
remove_if(
|
remove_if(
|
||||||
_block.statements.begin() + index + 1,
|
_block.statements.begin() + index + 1,
|
||||||
_block.statements.end(),
|
_block.statements.end(),
|
||||||
[] (Statement const& _s) { return _s.type() != typeid(yul::FunctionDefinition); }
|
[] (Statement const& _s) { return !holds_alternative<yul::FunctionDefinition>(_s); }
|
||||||
),
|
),
|
||||||
_block.statements.end()
|
_block.statements.end()
|
||||||
);
|
);
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include <libyul/optimiser/ASTCopier.h>
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
#include <libyul/optimiser/NameDispenser.h>
|
#include <libyul/optimiser/NameDispenser.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
@ -49,9 +49,9 @@ void ExpressionInliner::operator()(FunctionDefinition& _fun)
|
|||||||
void ExpressionInliner::visit(Expression& _expression)
|
void ExpressionInliner::visit(Expression& _expression)
|
||||||
{
|
{
|
||||||
ASTModifier::visit(_expression);
|
ASTModifier::visit(_expression);
|
||||||
if (_expression.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_expression))
|
||||||
{
|
{
|
||||||
FunctionCall& funCall = boost::get<FunctionCall>(_expression);
|
FunctionCall& funCall = std::get<FunctionCall>(_expression);
|
||||||
if (!m_inlinableFunctions.count(funCall.functionName.name))
|
if (!m_inlinableFunctions.count(funCall.functionName.name))
|
||||||
return;
|
return;
|
||||||
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
|
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
|
||||||
@ -74,6 +74,6 @@ void ExpressionInliner::visit(Expression& _expression)
|
|||||||
substitutions[paraName] = &arg;
|
substitutions[paraName] = &arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
_expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value);
|
_expression = Substitution(substitutions).translate(*std::get<Assignment>(fun.body.statements.front()).value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,7 @@
|
|||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/AsmDataForward.h>
|
#include <libyul/AsmDataForward.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
namespace yul
|
namespace yul
|
||||||
|
@ -61,12 +61,12 @@ void ExpressionJoiner::operator()(Block& _block)
|
|||||||
|
|
||||||
void ExpressionJoiner::visit(Expression& _e)
|
void ExpressionJoiner::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier const& identifier = boost::get<Identifier>(_e);
|
Identifier const& identifier = std::get<Identifier>(_e);
|
||||||
if (isLatestStatementVarDeclJoinable(identifier))
|
if (isLatestStatementVarDeclJoinable(identifier))
|
||||||
{
|
{
|
||||||
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(*latestStatement());
|
VariableDeclaration& varDecl = std::get<VariableDeclaration>(*latestStatement());
|
||||||
_e = std::move(*varDecl.value);
|
_e = std::move(*varDecl.value);
|
||||||
|
|
||||||
// Delete the variable declaration (also get the moved-from structure back into a sane state)
|
// Delete the variable declaration (also get the moved-from structure back into a sane state)
|
||||||
@ -96,7 +96,7 @@ void ExpressionJoiner::handleArguments(vector<Expression>& _arguments)
|
|||||||
for (Expression const& arg: _arguments | boost::adaptors::reversed)
|
for (Expression const& arg: _arguments | boost::adaptors::reversed)
|
||||||
{
|
{
|
||||||
--i;
|
--i;
|
||||||
if (arg.type() != typeid(Identifier) && arg.type() != typeid(Literal))
|
if (!holds_alternative<Identifier>(arg) && !holds_alternative<Literal>(arg))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// i points to the last element that is neither an identifier nor a literal,
|
// i points to the last element that is neither an identifier nor a literal,
|
||||||
@ -133,9 +133,9 @@ Statement* ExpressionJoiner::latestStatement()
|
|||||||
bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
|
bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
Statement const* statement = latestStatement();
|
Statement const* statement = latestStatement();
|
||||||
if (!statement || statement->type() != typeid(VariableDeclaration))
|
if (!statement || !holds_alternative<VariableDeclaration>(*statement))
|
||||||
return false;
|
return false;
|
||||||
VariableDeclaration const& varDecl = boost::get<VariableDeclaration>(*statement);
|
VariableDeclaration const& varDecl = std::get<VariableDeclaration>(*statement);
|
||||||
if (varDecl.variables.size() != 1 || !varDecl.value)
|
if (varDecl.variables.size() != 1 || !varDecl.value)
|
||||||
return false;
|
return false;
|
||||||
assertThrow(varDecl.variables.size() == 1, OptimizerException, "");
|
assertThrow(varDecl.variables.size() == 1, OptimizerException, "");
|
||||||
|
@ -95,7 +95,7 @@ void ExpressionSplitter::operator()(Block& _block)
|
|||||||
|
|
||||||
void ExpressionSplitter::outlineExpression(Expression& _expr)
|
void ExpressionSplitter::outlineExpression(Expression& _expr)
|
||||||
{
|
{
|
||||||
if (_expr.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_expr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
visit(_expr);
|
visit(_expr);
|
||||||
|
@ -33,8 +33,8 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
m_dialect.booleanNegationFunction() &&
|
m_dialect.booleanNegationFunction() &&
|
||||||
_forLoop.condition->type() != typeid(Literal) &&
|
!holds_alternative<Literal>(*_forLoop.condition) &&
|
||||||
_forLoop.condition->type() != typeid(Identifier)
|
!holds_alternative<Identifier>(*_forLoop.condition)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
langutil::SourceLocation const loc = locationOf(*_forLoop.condition);
|
langutil::SourceLocation const loc = locationOf(*_forLoop.condition);
|
||||||
|
@ -36,17 +36,17 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!m_dialect.booleanNegationFunction() ||
|
!m_dialect.booleanNegationFunction() ||
|
||||||
_forLoop.condition->type() != typeid(Literal) ||
|
!holds_alternative<Literal>(*_forLoop.condition) ||
|
||||||
valueOfLiteral(boost::get<Literal>(*_forLoop.condition)) == u256(0) ||
|
valueOfLiteral(std::get<Literal>(*_forLoop.condition)) == u256(0) ||
|
||||||
_forLoop.body.statements.empty() ||
|
_forLoop.body.statements.empty() ||
|
||||||
_forLoop.body.statements.front().type() != typeid(If)
|
!holds_alternative<If>(_forLoop.body.statements.front())
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
If& firstStatement = boost::get<If>(_forLoop.body.statements.front());
|
If& firstStatement = std::get<If>(_forLoop.body.statements.front());
|
||||||
if (
|
if (
|
||||||
firstStatement.body.statements.empty() ||
|
firstStatement.body.statements.empty() ||
|
||||||
firstStatement.body.statements.front().type() != typeid(Break)
|
!holds_alternative<Break>(firstStatement.body.statements.front())
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable())
|
if (!SideEffectsCollector(m_dialect, *firstStatement.condition).movable())
|
||||||
@ -56,10 +56,10 @@ void ForLoopConditionOutOfBody::operator()(ForLoop& _forLoop)
|
|||||||
langutil::SourceLocation location = locationOf(*firstStatement.condition);
|
langutil::SourceLocation location = locationOf(*firstStatement.condition);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
firstStatement.condition->type() == typeid(FunctionCall) &&
|
holds_alternative<FunctionCall>(*firstStatement.condition) &&
|
||||||
boost::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero
|
std::get<FunctionCall>(*firstStatement.condition).functionName.name == iszero
|
||||||
)
|
)
|
||||||
_forLoop.condition = make_unique<Expression>(std::move(boost::get<FunctionCall>(*firstStatement.condition).arguments.front()));
|
_forLoop.condition = make_unique<Expression>(std::move(std::get<FunctionCall>(*firstStatement.condition).arguments.front()));
|
||||||
else
|
else
|
||||||
_forLoop.condition = make_unique<Expression>(FunctionCall{
|
_forLoop.condition = make_unique<Expression>(FunctionCall{
|
||||||
location,
|
location,
|
||||||
|
@ -29,9 +29,9 @@ void ForLoopInitRewriter::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[&](Statement& _stmt) -> std::optional<vector<Statement>>
|
[&](Statement& _stmt) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
if (_stmt.type() == typeid(ForLoop))
|
if (holds_alternative<ForLoop>(_stmt))
|
||||||
{
|
{
|
||||||
auto& forLoop = boost::get<ForLoop>(_stmt);
|
auto& forLoop = std::get<ForLoop>(_stmt);
|
||||||
(*this)(forLoop.pre);
|
(*this)(forLoop.pre);
|
||||||
(*this)(forLoop.body);
|
(*this)(forLoop.body);
|
||||||
(*this)(forLoop.post);
|
(*this)(forLoop.post);
|
||||||
|
@ -51,7 +51,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
|||||||
SSAValueTracker tracker;
|
SSAValueTracker tracker;
|
||||||
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 && holds_alternative<Literal>(*ssaValue.second))
|
||||||
m_constants.emplace(ssaValue.first);
|
m_constants.emplace(ssaValue.first);
|
||||||
|
|
||||||
// Store size of global statements.
|
// Store size of global statements.
|
||||||
@ -59,9 +59,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
|||||||
map<YulString, 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 (!holds_alternative<FunctionDefinition>(statement))
|
||||||
continue;
|
continue;
|
||||||
FunctionDefinition& fun = boost::get<FunctionDefinition>(statement);
|
FunctionDefinition& fun = std::get<FunctionDefinition>(statement);
|
||||||
m_functions[fun.name] = &fun;
|
m_functions[fun.name] = &fun;
|
||||||
if (LeaveFinder::containsLeave(fun))
|
if (LeaveFinder::containsLeave(fun))
|
||||||
m_noInlineFunctions.insert(fun.name);
|
m_noInlineFunctions.insert(fun.name);
|
||||||
@ -75,8 +75,8 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
|
|||||||
void FullInliner::run()
|
void FullInliner::run()
|
||||||
{
|
{
|
||||||
for (auto& statement: m_ast.statements)
|
for (auto& statement: m_ast.statements)
|
||||||
if (statement.type() == typeid(Block))
|
if (holds_alternative<Block>(statement))
|
||||||
handleBlock({}, boost::get<Block>(statement));
|
handleBlock({}, std::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.
|
||||||
@ -115,9 +115,9 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
|||||||
// Constant arguments might provide a means for further optimization, so they cause a bonus.
|
// Constant arguments might provide a means for further optimization, so they cause a bonus.
|
||||||
bool constantArg = false;
|
bool constantArg = false;
|
||||||
for (auto const& argument: _funCall.arguments)
|
for (auto const& argument: _funCall.arguments)
|
||||||
if (argument.type() == typeid(Literal) || (
|
if (holds_alternative<Literal>(argument) || (
|
||||||
argument.type() == typeid(Identifier) &&
|
holds_alternative<Identifier>(argument) &&
|
||||||
m_constants.count(boost::get<Identifier>(argument).name)
|
m_constants.count(std::get<Identifier>(argument).name)
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
constantArg = true;
|
constantArg = true;
|
||||||
@ -160,7 +160,7 @@ void InlineModifier::operator()(Block& _block)
|
|||||||
std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement)
|
std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _statement)
|
||||||
{
|
{
|
||||||
// Only inline for expression statements, assignments and variable declarations.
|
// Only inline for expression statements, assignments and variable declarations.
|
||||||
Expression* e = boost::apply_visitor(GenericFallbackReturnsVisitor<Expression*, ExpressionStatement, Assignment, VariableDeclaration>(
|
Expression* e = std::visit(GenericFallbackReturnsVisitor<Expression*, ExpressionStatement, Assignment, VariableDeclaration>(
|
||||||
[](ExpressionStatement& _s) { return &_s.expression; },
|
[](ExpressionStatement& _s) { return &_s.expression; },
|
||||||
[](Assignment& _s) { return _s.value.get(); },
|
[](Assignment& _s) { return _s.value.get(); },
|
||||||
[](VariableDeclaration& _s) { return _s.value.get(); }
|
[](VariableDeclaration& _s) { return _s.value.get(); }
|
||||||
@ -168,7 +168,7 @@ std::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement& _
|
|||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
// Only inline direct function calls.
|
// Only inline direct function calls.
|
||||||
FunctionCall* funCall = boost::apply_visitor(GenericFallbackReturnsVisitor<FunctionCall*, FunctionCall&>(
|
FunctionCall* funCall = std::visit(GenericFallbackReturnsVisitor<FunctionCall*, FunctionCall&>(
|
||||||
[](FunctionCall& _e) { return &_e; }
|
[](FunctionCall& _e) { return &_e; }
|
||||||
), *e);
|
), *e);
|
||||||
if (funCall && m_driver.shallInline(*funCall, m_currentFunction))
|
if (funCall && m_driver.shallInline(*funCall, m_currentFunction))
|
||||||
@ -206,9 +206,9 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC
|
|||||||
newVariable(var, nullptr);
|
newVariable(var, nullptr);
|
||||||
|
|
||||||
Statement newBody = BodyCopier(m_nameDispenser, variableReplacements)(function->body);
|
Statement newBody = BodyCopier(m_nameDispenser, variableReplacements)(function->body);
|
||||||
newStatements += std::move(boost::get<Block>(newBody).statements);
|
newStatements += std::move(std::get<Block>(newBody).statements);
|
||||||
|
|
||||||
boost::apply_visitor(GenericFallbackVisitor<Assignment, VariableDeclaration>{
|
std::visit(GenericFallbackVisitor<Assignment, VariableDeclaration>{
|
||||||
[&](Assignment& _assignment)
|
[&](Assignment& _assignment)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < _assignment.variableNames.size(); ++i)
|
for (size_t i = 0; i < _assignment.variableNames.size(); ++i)
|
||||||
|
@ -29,8 +29,6 @@
|
|||||||
|
|
||||||
#include <liblangutil/SourceLocation.h>
|
#include <liblangutil/SourceLocation.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ void FunctionGrouper::operator()(Block& _block)
|
|||||||
|
|
||||||
for (auto&& statement: _block.statements)
|
for (auto&& statement: _block.statements)
|
||||||
{
|
{
|
||||||
if (statement.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(statement))
|
||||||
reordered.emplace_back(std::move(statement));
|
reordered.emplace_back(std::move(statement));
|
||||||
else
|
else
|
||||||
boost::get<Block>(reordered.front()).statements.emplace_back(std::move(statement));
|
std::get<Block>(reordered.front()).statements.emplace_back(std::move(statement));
|
||||||
}
|
}
|
||||||
_block.statements = std::move(reordered);
|
_block.statements = std::move(reordered);
|
||||||
}
|
}
|
||||||
@ -52,10 +52,10 @@ bool FunctionGrouper::alreadyGrouped(Block const& _block)
|
|||||||
{
|
{
|
||||||
if (_block.statements.empty())
|
if (_block.statements.empty())
|
||||||
return false;
|
return false;
|
||||||
if (_block.statements.front().type() != typeid(Block))
|
if (!holds_alternative<Block>(_block.statements.front()))
|
||||||
return false;
|
return false;
|
||||||
for (size_t i = 1; i < _block.statements.size(); ++i)
|
for (size_t i = 1; i < _block.statements.size(); ++i)
|
||||||
if (_block.statements.at(i).type() != typeid(FunctionDefinition))
|
if (!holds_alternative<FunctionDefinition>(_block.statements.at(i)))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ void FunctionHoister::operator()(Block& _block)
|
|||||||
m_isTopLevel = false;
|
m_isTopLevel = false;
|
||||||
for (auto&& statement: _block.statements)
|
for (auto&& statement: _block.statements)
|
||||||
{
|
{
|
||||||
boost::apply_visitor(*this, statement);
|
std::visit(*this, statement);
|
||||||
if (statement.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(statement))
|
||||||
{
|
{
|
||||||
m_functions.emplace_back(std::move(statement));
|
m_functions.emplace_back(std::move(statement));
|
||||||
statement = Block{_block.location, {}};
|
statement = Block{_block.location, {}};
|
||||||
|
@ -45,9 +45,9 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
|
|||||||
{
|
{
|
||||||
YulString 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 (holds_alternative<Assignment>(bodyStatement))
|
||||||
{
|
{
|
||||||
Assignment const& assignment = boost::get<Assignment>(bodyStatement);
|
Assignment const& assignment = std::get<Assignment>(bodyStatement);
|
||||||
if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable)
|
if (assignment.variableNames.size() == 1 && assignment.variableNames.front().name == retVariable)
|
||||||
{
|
{
|
||||||
// TODO: use code size metric here
|
// TODO: use code size metric here
|
||||||
@ -57,7 +57,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
|
|||||||
// function body.
|
// function body.
|
||||||
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
|
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
|
||||||
m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
|
m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
|
||||||
boost::apply_visitor(*this, *assignment.value);
|
std::visit(*this, *assignment.value);
|
||||||
if (!m_foundDisallowedIdentifier)
|
if (!m_foundDisallowedIdentifier)
|
||||||
m_inlinableFunctions[_function.name] = &_function;
|
m_inlinableFunctions[_function.name] = &_function;
|
||||||
m_disallowedIdentifiers.clear();
|
m_disallowedIdentifiers.clear();
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
|
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
|
|
||||||
@ -37,12 +40,12 @@ bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
|
|||||||
// If that fails, try `eq(_a, _b)`.
|
// If that fails, try `eq(_a, _b)`.
|
||||||
|
|
||||||
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
||||||
if (expr1.type() == typeid(Literal))
|
if (holds_alternative<Literal>(expr1))
|
||||||
return valueOfLiteral(boost::get<Literal>(expr1)) != 0;
|
return valueOfLiteral(std::get<Literal>(expr1)) != 0;
|
||||||
|
|
||||||
Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
Expression expr2 = simplify(FunctionCall{{}, {{}, "eq"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
||||||
if (expr2.type() == typeid(Literal))
|
if (holds_alternative<Literal>(expr2))
|
||||||
return valueOfLiteral(boost::get<Literal>(expr2)) == 0;
|
return valueOfLiteral(std::get<Literal>(expr2)) == 0;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -53,9 +56,9 @@ bool KnowledgeBase::knownToBeDifferentByAtLeast32(YulString _a, YulString _b)
|
|||||||
// current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32.
|
// current values to turn `sub(_a, _b)` into a constant whose absolute value is at least 32.
|
||||||
|
|
||||||
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
Expression expr1 = simplify(FunctionCall{{}, {{}, "sub"_yulstring}, make_vector<Expression>(Identifier{{}, _a}, Identifier{{}, _b})});
|
||||||
if (expr1.type() == typeid(Literal))
|
if (holds_alternative<Literal>(expr1))
|
||||||
{
|
{
|
||||||
u256 val = valueOfLiteral(boost::get<Literal>(expr1));
|
u256 val = valueOfLiteral(std::get<Literal>(expr1));
|
||||||
return val >= 32 && val <= u256(0) - 32;
|
return val >= 32 && val <= u256(0) - 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +77,8 @@ Expression KnowledgeBase::simplify(Expression _expression)
|
|||||||
else
|
else
|
||||||
--m_recursionCounter;
|
--m_recursionCounter;
|
||||||
|
|
||||||
if (_expression.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_expression))
|
||||||
for (Expression& arg: boost::get<FunctionCall>(_expression).arguments)
|
for (Expression& arg: std::get<FunctionCall>(_expression).arguments)
|
||||||
arg = simplify(arg);
|
arg = simplify(arg);
|
||||||
|
|
||||||
if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues))
|
if (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_variableValues))
|
||||||
|
@ -48,9 +48,9 @@ void LoadResolver::visit(Expression& _e)
|
|||||||
if (!dynamic_cast<EVMDialect const*>(&m_dialect))
|
if (!dynamic_cast<EVMDialect const*>(&m_dialect))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_e.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_e))
|
||||||
{
|
{
|
||||||
FunctionCall const& funCall = boost::get<FunctionCall>(_e);
|
FunctionCall const& funCall = std::get<FunctionCall>(_e);
|
||||||
if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name))
|
if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name))
|
||||||
if (builtin->instruction)
|
if (builtin->instruction)
|
||||||
tryResolve(_e, *builtin->instruction, funCall.arguments);
|
tryResolve(_e, *builtin->instruction, funCall.arguments);
|
||||||
@ -63,10 +63,10 @@ void LoadResolver::tryResolve(
|
|||||||
vector<Expression> const& _arguments
|
vector<Expression> const& _arguments
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier))
|
if (_arguments.empty() || !holds_alternative<Identifier>(_arguments.at(0)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
YulString key = boost::get<Identifier>(_arguments.at(0)).name;
|
YulString key = std::get<Identifier>(_arguments.at(0)).name;
|
||||||
if (
|
if (
|
||||||
_instruction == dev::eth::Instruction::SLOAD &&
|
_instruction == dev::eth::Instruction::SLOAD &&
|
||||||
m_storage.values.count(key)
|
m_storage.values.count(key)
|
||||||
|
@ -35,13 +35,13 @@ using namespace yul;
|
|||||||
void MainFunction::operator()(Block& _block)
|
void MainFunction::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
assertThrow(_block.statements.size() >= 1, OptimizerException, "");
|
assertThrow(_block.statements.size() >= 1, OptimizerException, "");
|
||||||
assertThrow(_block.statements[0].type() == typeid(Block), OptimizerException, "");
|
assertThrow(holds_alternative<Block>(_block.statements[0]), OptimizerException, "");
|
||||||
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(holds_alternative<FunctionDefinition>(_block.statements.at(i)), 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"_yulstring) == 0, OptimizerException, "");
|
assertThrow(NameCollector(_block).names().count("main"_yulstring) == 0, OptimizerException, "");
|
||||||
|
|
||||||
Block& block = boost::get<Block>(_block.statements[0]);
|
Block& block = std::get<Block>(_block.statements[0]);
|
||||||
FunctionDefinition main{
|
FunctionDefinition main{
|
||||||
block.location,
|
block.location,
|
||||||
"main"_yulstring,
|
"main"_yulstring,
|
||||||
|
@ -65,24 +65,24 @@ size_t CodeSize::codeSizeIncludingFunctions(Block const& _block)
|
|||||||
|
|
||||||
void CodeSize::visit(Statement const& _statement)
|
void CodeSize::visit(Statement const& _statement)
|
||||||
{
|
{
|
||||||
if (_statement.type() == typeid(FunctionDefinition) && m_ignoreFunctions)
|
if (holds_alternative<FunctionDefinition>(_statement) && m_ignoreFunctions)
|
||||||
return;
|
return;
|
||||||
else if (
|
else if (
|
||||||
_statement.type() == typeid(If) ||
|
holds_alternative<If>(_statement) ||
|
||||||
_statement.type() == typeid(Break) ||
|
holds_alternative<Break>(_statement) ||
|
||||||
_statement.type() == typeid(Continue) ||
|
holds_alternative<Continue>(_statement) ||
|
||||||
_statement.type() == typeid(Leave)
|
holds_alternative<Leave>(_statement)
|
||||||
)
|
)
|
||||||
m_size += 2;
|
m_size += 2;
|
||||||
else if (_statement.type() == typeid(ForLoop))
|
else if (holds_alternative<ForLoop>(_statement))
|
||||||
m_size += 3;
|
m_size += 3;
|
||||||
else if (_statement.type() == typeid(Switch))
|
else if (holds_alternative<Switch>(_statement))
|
||||||
m_size += 1 + 2 * boost::get<Switch>(_statement).cases.size();
|
m_size += 1 + 2 * std::get<Switch>(_statement).cases.size();
|
||||||
else if (!(
|
else if (!(
|
||||||
_statement.type() == typeid(Block) ||
|
holds_alternative<Block>(_statement) ||
|
||||||
_statement.type() == typeid(ExpressionStatement) ||
|
holds_alternative<ExpressionStatement>(_statement) ||
|
||||||
_statement.type() == typeid(Assignment) ||
|
holds_alternative<Assignment>(_statement) ||
|
||||||
_statement.type() == typeid(VariableDeclaration)
|
holds_alternative<VariableDeclaration>(_statement)
|
||||||
))
|
))
|
||||||
++m_size;
|
++m_size;
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ void CodeSize::visit(Statement const& _statement)
|
|||||||
|
|
||||||
void CodeSize::visit(Expression const& _expression)
|
void CodeSize::visit(Expression const& _expression)
|
||||||
{
|
{
|
||||||
if (_expression.type() != typeid(Identifier))
|
if (!holds_alternative<Identifier>(_expression))
|
||||||
++m_size;
|
++m_size;
|
||||||
ASTWalker::visit(_expression);
|
ASTWalker::visit(_expression);
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,8 @@ void NameDisplacer::operator()(Block& _block)
|
|||||||
// First replace all the names of function definitions
|
// First replace all the names of function definitions
|
||||||
// because of scoping.
|
// because of scoping.
|
||||||
for (auto& st: _block.statements)
|
for (auto& st: _block.statements)
|
||||||
if (st.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(st))
|
||||||
checkAndReplaceNew(boost::get<FunctionDefinition>(st).name);
|
checkAndReplaceNew(std::get<FunctionDefinition>(st).name);
|
||||||
|
|
||||||
ASTModifier::operator()(_block);
|
ASTModifier::operator()(_block);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ using namespace yul;
|
|||||||
void yul::removeEmptyBlocks(Block& _block)
|
void yul::removeEmptyBlocks(Block& _block)
|
||||||
{
|
{
|
||||||
auto isEmptyBlock = [](Statement const& _st) -> bool {
|
auto isEmptyBlock = [](Statement const& _st) -> bool {
|
||||||
return _st.type() == typeid(Block) && boost::get<Block>(_st).statements.empty();
|
return holds_alternative<Block>(_st) && std::get<Block>(_st).statements.empty();
|
||||||
};
|
};
|
||||||
boost::range::remove_erase_if(_block.statements, isEmptyBlock);
|
boost::range::remove_erase_if(_block.statements, isEmptyBlock);
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ void RedundantAssignEliminator::finalize(
|
|||||||
void AssignmentRemover::operator()(Block& _block)
|
void AssignmentRemover::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool {
|
boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool {
|
||||||
return _statement.type() == typeid(Assignment) && m_toRemove.count(&boost::get<Assignment>(_statement));
|
return holds_alternative<Assignment>(_statement) && m_toRemove.count(&std::get<Assignment>(_statement));
|
||||||
});
|
});
|
||||||
|
|
||||||
ASTModifier::operator()(_block);
|
ASTModifier::operator()(_block);
|
||||||
|
@ -68,9 +68,9 @@ Rematerialiser::Rematerialiser(
|
|||||||
|
|
||||||
void Rematerialiser::visit(Expression& _e)
|
void Rematerialiser::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier& identifier = boost::get<Identifier>(_e);
|
Identifier& identifier = std::get<Identifier>(_e);
|
||||||
YulString name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
@ -96,15 +96,15 @@ void Rematerialiser::visit(Expression& _e)
|
|||||||
|
|
||||||
void LiteralRematerialiser::visit(Expression& _e)
|
void LiteralRematerialiser::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
Identifier& identifier = boost::get<Identifier>(_e);
|
Identifier& identifier = std::get<Identifier>(_e);
|
||||||
YulString name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
Expression const* value = m_value.at(name);
|
Expression const* value = m_value.at(name);
|
||||||
assertThrow(value, OptimizerException, "");
|
assertThrow(value, OptimizerException, "");
|
||||||
if (value->type() == typeid(Literal))
|
if (holds_alternative<Literal>(*value))
|
||||||
_e = *value;
|
_e = *value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libdevcore/CommonData.h>
|
#include <libdevcore/CommonData.h>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul;
|
using namespace yul;
|
||||||
@ -37,7 +39,7 @@ void SSAReverser::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
|
[&](Statement& _stmt1, Statement& _stmt2) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
auto* varDecl = boost::get<VariableDeclaration>(&_stmt1);
|
auto* varDecl = std::get_if<VariableDeclaration>(&_stmt1);
|
||||||
|
|
||||||
if (!varDecl || varDecl->variables.size() != 1 || !varDecl->value)
|
if (!varDecl || varDecl->variables.size() != 1 || !varDecl->value)
|
||||||
return {};
|
return {};
|
||||||
@ -48,9 +50,9 @@ void SSAReverser::operator()(Block& _block)
|
|||||||
// with
|
// with
|
||||||
// a := E
|
// a := E
|
||||||
// let a_1 := a
|
// let a_1 := a
|
||||||
if (auto* assignment = boost::get<Assignment>(&_stmt2))
|
if (auto* assignment = std::get_if<Assignment>(&_stmt2))
|
||||||
{
|
{
|
||||||
auto* identifier = boost::get<Identifier>(assignment->value.get());
|
auto* identifier = std::get_if<Identifier>(assignment->value.get());
|
||||||
if (
|
if (
|
||||||
assignment->variableNames.size() == 1 &&
|
assignment->variableNames.size() == 1 &&
|
||||||
identifier &&
|
identifier &&
|
||||||
@ -81,9 +83,9 @@ void SSAReverser::operator()(Block& _block)
|
|||||||
// with
|
// with
|
||||||
// let a := E
|
// let a := E
|
||||||
// let a_1 := a
|
// let a_1 := a
|
||||||
else if (auto* varDecl2 = boost::get<VariableDeclaration>(&_stmt2))
|
else if (auto* varDecl2 = std::get_if<VariableDeclaration>(&_stmt2))
|
||||||
{
|
{
|
||||||
auto* identifier = boost::get<Identifier>(varDecl2->value.get());
|
auto* identifier = std::get_if<Identifier>(varDecl2->value.get());
|
||||||
if (
|
if (
|
||||||
varDecl2->variables.size() == 1 &&
|
varDecl2->variables.size() == 1 &&
|
||||||
identifier &&
|
identifier &&
|
||||||
|
@ -60,9 +60,9 @@ void IntroduceSSA::operator()(Block& _block)
|
|||||||
_block.statements,
|
_block.statements,
|
||||||
[&](Statement& _s) -> std::optional<vector<Statement>>
|
[&](Statement& _s) -> std::optional<vector<Statement>>
|
||||||
{
|
{
|
||||||
if (_s.type() == typeid(VariableDeclaration))
|
if (holds_alternative<VariableDeclaration>(_s))
|
||||||
{
|
{
|
||||||
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s);
|
VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
|
||||||
if (varDecl.value)
|
if (varDecl.value)
|
||||||
visit(*varDecl.value);
|
visit(*varDecl.value);
|
||||||
|
|
||||||
@ -90,12 +90,12 @@ void IntroduceSSA::operator()(Block& _block)
|
|||||||
make_unique<Expression>(Identifier{loc, newName})
|
make_unique<Expression>(Identifier{loc, newName})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
boost::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
|
std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
|
||||||
return { std::move(statements) };
|
return { std::move(statements) };
|
||||||
}
|
}
|
||||||
else if (_s.type() == typeid(Assignment))
|
else if (holds_alternative<Assignment>(_s))
|
||||||
{
|
{
|
||||||
Assignment& assignment = boost::get<Assignment>(_s);
|
Assignment& assignment = std::get<Assignment>(_s);
|
||||||
visit(*assignment.value);
|
visit(*assignment.value);
|
||||||
for (auto const& var: assignment.variableNames)
|
for (auto const& var: assignment.variableNames)
|
||||||
assertThrow(m_variablesToReplace.count(var.name), OptimizerException, "");
|
assertThrow(m_variablesToReplace.count(var.name), OptimizerException, "");
|
||||||
@ -117,7 +117,7 @@ void IntroduceSSA::operator()(Block& _block)
|
|||||||
make_unique<Expression>(Identifier{loc, newName})
|
make_unique<Expression>(Identifier{loc, newName})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
boost::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
|
std::get<VariableDeclaration>(statements.front()).variables = std::move(newVariables);
|
||||||
return { std::move(statements) };
|
return { std::move(statements) };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -228,9 +228,9 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
|
|||||||
}
|
}
|
||||||
m_variablesToReassign.clear();
|
m_variablesToReassign.clear();
|
||||||
|
|
||||||
if (_s.type() == typeid(VariableDeclaration))
|
if (holds_alternative<VariableDeclaration>(_s))
|
||||||
{
|
{
|
||||||
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_s);
|
VariableDeclaration& varDecl = std::get<VariableDeclaration>(_s);
|
||||||
for (auto const& var: varDecl.variables)
|
for (auto const& var: varDecl.variables)
|
||||||
if (m_variablesToReplace.count(var.name))
|
if (m_variablesToReplace.count(var.name))
|
||||||
{
|
{
|
||||||
@ -238,9 +238,9 @@ void IntroduceControlFlowSSA::operator()(Block& _block)
|
|||||||
m_variablesInScope.insert(var.name);
|
m_variablesInScope.insert(var.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_s.type() == typeid(Assignment))
|
else if (holds_alternative<Assignment>(_s))
|
||||||
{
|
{
|
||||||
Assignment& assignment = boost::get<Assignment>(_s);
|
Assignment& assignment = std::get<Assignment>(_s);
|
||||||
for (auto const& var: assignment.variableNames)
|
for (auto const& var: assignment.variableNames)
|
||||||
if (m_variablesToReplace.count(var.name))
|
if (m_variablesToReplace.count(var.name))
|
||||||
assignedVariables.insert(var.name);
|
assignedVariables.insert(var.name);
|
||||||
@ -304,14 +304,14 @@ void PropagateValues::operator()(VariableDeclaration& _varDecl)
|
|||||||
if (m_variablesToReplace.count(variable))
|
if (m_variablesToReplace.count(variable))
|
||||||
{
|
{
|
||||||
// `let a := a_1` - regular declaration of non-SSA variable
|
// `let a := a_1` - regular declaration of non-SSA variable
|
||||||
yulAssert(_varDecl.value->type() == typeid(Identifier), "");
|
yulAssert(holds_alternative<Identifier>(*_varDecl.value), "");
|
||||||
m_currentVariableValues[variable] = boost::get<Identifier>(*_varDecl.value).name;
|
m_currentVariableValues[variable] = std::get<Identifier>(*_varDecl.value).name;
|
||||||
m_clearAtEndOfBlock.insert(variable);
|
m_clearAtEndOfBlock.insert(variable);
|
||||||
}
|
}
|
||||||
else if (_varDecl.value && _varDecl.value->type() == typeid(Identifier))
|
else if (_varDecl.value && holds_alternative<Identifier>(*_varDecl.value))
|
||||||
{
|
{
|
||||||
// `let a_1 := a` - assignment to SSA variable after a branch.
|
// `let a_1 := a` - assignment to SSA variable after a branch.
|
||||||
YulString value = boost::get<Identifier>(*_varDecl.value).name;
|
YulString value = std::get<Identifier>(*_varDecl.value).name;
|
||||||
if (m_variablesToReplace.count(value))
|
if (m_variablesToReplace.count(value))
|
||||||
{
|
{
|
||||||
// This is safe because `a_1` is not a "variable to replace" and thus
|
// This is safe because `a_1` is not a "variable to replace" and thus
|
||||||
@ -333,8 +333,8 @@ void PropagateValues::operator()(Assignment& _assignment)
|
|||||||
if (!m_variablesToReplace.count(name))
|
if (!m_variablesToReplace.count(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
yulAssert(_assignment.value && _assignment.value->type() == typeid(Identifier), "");
|
yulAssert(_assignment.value && holds_alternative<Identifier>(*_assignment.value), "");
|
||||||
m_currentVariableValues[name] = boost::get<Identifier>(*_assignment.value).name;
|
m_currentVariableValues[name] = std::get<Identifier>(*_assignment.value).name;
|
||||||
m_clearAtEndOfBlock.insert(name);
|
m_clearAtEndOfBlock.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,15 +150,15 @@ pair<TerminationFinder::ControlFlow, size_t> TerminationFinder::firstUncondition
|
|||||||
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
|
TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
_statement.type() == typeid(ExpressionStatement) &&
|
holds_alternative<ExpressionStatement>(_statement) &&
|
||||||
isTerminatingBuiltin(boost::get<ExpressionStatement>(_statement))
|
isTerminatingBuiltin(std::get<ExpressionStatement>(_statement))
|
||||||
)
|
)
|
||||||
return ControlFlow::Terminate;
|
return ControlFlow::Terminate;
|
||||||
else if (_statement.type() == typeid(Break))
|
else if (holds_alternative<Break>(_statement))
|
||||||
return ControlFlow::Break;
|
return ControlFlow::Break;
|
||||||
else if (_statement.type() == typeid(Continue))
|
else if (holds_alternative<Continue>(_statement))
|
||||||
return ControlFlow::Continue;
|
return ControlFlow::Continue;
|
||||||
else if (_statement.type() == typeid(Leave))
|
else if (holds_alternative<Leave>(_statement))
|
||||||
return ControlFlow::Leave;
|
return ControlFlow::Leave;
|
||||||
else
|
else
|
||||||
return ControlFlow::FlowOut;
|
return ControlFlow::FlowOut;
|
||||||
@ -166,9 +166,9 @@ TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement cons
|
|||||||
|
|
||||||
bool TerminationFinder::isTerminatingBuiltin(ExpressionStatement const& _exprStmnt)
|
bool TerminationFinder::isTerminatingBuiltin(ExpressionStatement const& _exprStmnt)
|
||||||
{
|
{
|
||||||
if (_exprStmnt.expression.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_exprStmnt.expression))
|
||||||
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
|
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
|
||||||
if (auto const* builtin = dialect->builtin(boost::get<FunctionCall>(_exprStmnt.expression).functionName.name))
|
if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_exprStmnt.expression).functionName.name))
|
||||||
if (builtin->instruction)
|
if (builtin->instruction)
|
||||||
return eth::SemanticInformation::terminatesControlFlow(*builtin->instruction);
|
return eth::SemanticInformation::terminatesControlFlow(*builtin->instruction);
|
||||||
return false;
|
return false;
|
||||||
|
@ -67,11 +67,11 @@ bool SimplificationRules::isInitialized() const
|
|||||||
std::optional<std::pair<dev::eth::Instruction, vector<Expression> const*>>
|
std::optional<std::pair<dev::eth::Instruction, vector<Expression> const*>>
|
||||||
SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
|
SimplificationRules::instructionAndArguments(Dialect const& _dialect, Expression const& _expr)
|
||||||
{
|
{
|
||||||
if (_expr.type() == typeid(FunctionCall))
|
if (holds_alternative<FunctionCall>(_expr))
|
||||||
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
if (auto const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
||||||
if (auto const* builtin = dialect->builtin(boost::get<FunctionCall>(_expr).functionName.name))
|
if (auto const* builtin = dialect->builtin(std::get<FunctionCall>(_expr).functionName.name))
|
||||||
if (builtin->instruction)
|
if (builtin->instruction)
|
||||||
return make_pair(*builtin->instruction, &boost::get<FunctionCall>(_expr).arguments);
|
return make_pair(*builtin->instruction, &std::get<FunctionCall>(_expr).arguments);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -134,9 +134,9 @@ bool Pattern::matches(
|
|||||||
|
|
||||||
// Resolve the variable if possible.
|
// Resolve the variable if possible.
|
||||||
// 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 && holds_alternative<Identifier>(_expr))
|
||||||
{
|
{
|
||||||
YulString varName = boost::get<Identifier>(_expr).name;
|
YulString varName = std::get<Identifier>(_expr).name;
|
||||||
if (_ssaValues.count(varName))
|
if (_ssaValues.count(varName))
|
||||||
if (Expression const* new_expr = _ssaValues.at(varName))
|
if (Expression const* new_expr = _ssaValues.at(varName))
|
||||||
expr = new_expr;
|
expr = new_expr;
|
||||||
@ -145,9 +145,9 @@ bool Pattern::matches(
|
|||||||
|
|
||||||
if (m_kind == PatternKind::Constant)
|
if (m_kind == PatternKind::Constant)
|
||||||
{
|
{
|
||||||
if (expr->type() != typeid(Literal))
|
if (!holds_alternative<Literal>(*expr))
|
||||||
return false;
|
return false;
|
||||||
Literal const& literal = boost::get<Literal>(*expr);
|
Literal const& literal = std::get<Literal>(*expr);
|
||||||
if (literal.kind != LiteralKind::Number)
|
if (literal.kind != LiteralKind::Number)
|
||||||
return false;
|
return false;
|
||||||
if (m_data && *m_data != u256(literal.value.str()))
|
if (m_data && *m_data != u256(literal.value.str()))
|
||||||
@ -238,7 +238,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
|
|||||||
|
|
||||||
u256 Pattern::d() const
|
u256 Pattern::d() const
|
||||||
{
|
{
|
||||||
return valueOfNumberLiteral(boost::get<Literal>(matchGroupValue()));
|
return valueOfNumberLiteral(std::get<Literal>(matchGroupValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression const& Pattern::matchGroupValue() const
|
Expression const& Pattern::matchGroupValue() const
|
||||||
|
@ -85,9 +85,9 @@ public:
|
|||||||
// get called on left-hand-sides of assignments.
|
// get called on left-hand-sides of assignments.
|
||||||
void visit(Expression& _e) override
|
void visit(Expression& _e) override
|
||||||
{
|
{
|
||||||
if (_e.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_e))
|
||||||
{
|
{
|
||||||
YulString name = boost::get<Identifier>(_e).name;
|
YulString name = std::get<Identifier>(_e).name;
|
||||||
if (m_expressionCodeCost.count(name))
|
if (m_expressionCodeCost.count(name))
|
||||||
{
|
{
|
||||||
if (!m_value.count(name))
|
if (!m_value.count(name))
|
||||||
@ -162,7 +162,7 @@ bool StackCompressor::run(
|
|||||||
{
|
{
|
||||||
yulAssert(
|
yulAssert(
|
||||||
_object.code &&
|
_object.code &&
|
||||||
_object.code->statements.size() > 0 && _object.code->statements.at(0).type() == typeid(Block),
|
_object.code->statements.size() > 0 && holds_alternative<Block>(_object.code->statements.at(0)),
|
||||||
"Need to run the function grouper before the stack compressor."
|
"Need to run the function grouper before the stack compressor."
|
||||||
);
|
);
|
||||||
bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code);
|
bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code);
|
||||||
@ -177,7 +177,7 @@ bool StackCompressor::run(
|
|||||||
yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value.");
|
yulAssert(stackSurplus.at({}) > 0, "Invalid surplus value.");
|
||||||
eliminateVariables(
|
eliminateVariables(
|
||||||
_dialect,
|
_dialect,
|
||||||
boost::get<Block>(_object.code->statements.at(0)),
|
std::get<Block>(_object.code->statements.at(0)),
|
||||||
stackSurplus.at({}),
|
stackSurplus.at({}),
|
||||||
allowMSizeOptimzation
|
allowMSizeOptimzation
|
||||||
);
|
);
|
||||||
@ -185,7 +185,7 @@ bool StackCompressor::run(
|
|||||||
|
|
||||||
for (size_t i = 1; i < _object.code->statements.size(); ++i)
|
for (size_t i = 1; i < _object.code->statements.size(); ++i)
|
||||||
{
|
{
|
||||||
FunctionDefinition& fun = boost::get<FunctionDefinition>(_object.code->statements[i]);
|
FunctionDefinition& fun = std::get<FunctionDefinition>(_object.code->statements[i]);
|
||||||
if (!stackSurplus.count(fun.name))
|
if (!stackSurplus.count(fun.name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
|
|||||||
_statements,
|
_statements,
|
||||||
[&](Statement& _stmt) -> OptionalStatements
|
[&](Statement& _stmt) -> OptionalStatements
|
||||||
{
|
{
|
||||||
OptionalStatements result = boost::apply_visitor(visitor, _stmt);
|
OptionalStatements result = std::visit(visitor, _stmt);
|
||||||
if (result)
|
if (result)
|
||||||
simplify(*result);
|
simplify(*result);
|
||||||
else
|
else
|
||||||
@ -123,8 +123,8 @@ bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression)
|
|||||||
|
|
||||||
std::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
|
std::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
|
||||||
{
|
{
|
||||||
if (_expression.type() == typeid(Literal))
|
if (holds_alternative<Literal>(_expression))
|
||||||
return valueOfLiteral(boost::get<Literal>(_expression));
|
return valueOfLiteral(std::get<Literal>(_expression));
|
||||||
else
|
else
|
||||||
return std::optional<u256>();
|
return std::optional<u256>();
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ using namespace yul;
|
|||||||
|
|
||||||
Expression Substitution::translate(Expression const& _expression)
|
Expression Substitution::translate(Expression const& _expression)
|
||||||
{
|
{
|
||||||
if (_expression.type() == typeid(Identifier))
|
if (holds_alternative<Identifier>(_expression))
|
||||||
{
|
{
|
||||||
YulString name = boost::get<Identifier>(_expression).name;
|
YulString name = std::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));
|
||||||
|
@ -80,7 +80,7 @@ void OptimiserSuite::run(
|
|||||||
set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
|
set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
|
||||||
reservedIdentifiers += _dialect.fixedFunctionNames();
|
reservedIdentifiers += _dialect.fixedFunctionNames();
|
||||||
|
|
||||||
*_object.code = boost::get<Block>(Disambiguator(
|
*_object.code = std::get<Block>(Disambiguator(
|
||||||
_dialect,
|
_dialect,
|
||||||
*_object.analysisInfo,
|
*_object.analysisInfo,
|
||||||
reservedIdentifiers
|
reservedIdentifiers
|
||||||
@ -291,7 +291,7 @@ void OptimiserSuite::run(
|
|||||||
{
|
{
|
||||||
// If the first statement is an empty block, remove it.
|
// If the first statement is an empty block, remove it.
|
||||||
// We should only have function definitions after that.
|
// We should only have function definitions after that.
|
||||||
if (ast.statements.size() > 1 && boost::get<Block>(ast.statements.front()).statements.empty())
|
if (ast.statements.size() > 1 && std::get<Block>(ast.statements.front()).statements.empty())
|
||||||
ast.statements.erase(ast.statements.begin());
|
ast.statements.erase(ast.statements.begin());
|
||||||
}
|
}
|
||||||
suite.runSequence({
|
suite.runSequence({
|
||||||
@ -361,7 +361,7 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
|
|||||||
{
|
{
|
||||||
unique_ptr<Block> copy;
|
unique_ptr<Block> copy;
|
||||||
if (m_debug == Debug::PrintChanges)
|
if (m_debug == Debug::PrintChanges)
|
||||||
copy = make_unique<Block>(boost::get<Block>(ASTCopier{}(_ast)));
|
copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
|
||||||
for (string const& step: _steps)
|
for (string const& step: _steps)
|
||||||
{
|
{
|
||||||
if (m_debug == Debug::PrintStep)
|
if (m_debug == Debug::PrintStep)
|
||||||
@ -376,7 +376,7 @@ void OptimiserSuite::runSequence(std::vector<string> const& _steps, Block& _ast)
|
|||||||
{
|
{
|
||||||
cout << "== Running " << step << " changed the AST." << endl;
|
cout << "== Running " << step << " changed the AST." << endl;
|
||||||
cout << AsmPrinter{}(_ast) << endl;
|
cout << AsmPrinter{}(_ast) << endl;
|
||||||
copy = make_unique<Block>(boost::get<Block>(ASTCopier{}(_ast)));
|
copy = make_unique<Block>(std::get<Block>(ASTCopier{}(_ast)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ using namespace yul;
|
|||||||
|
|
||||||
bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs)
|
bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool {
|
return std::visit([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool {
|
||||||
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
||||||
return this->expressionEqual(_lhsExpr, _rhsExpr);
|
return this->expressionEqual(_lhsExpr, _rhsExpr);
|
||||||
}, _lhs, _rhs);
|
}, _lhs, _rhs);
|
||||||
@ -40,7 +40,7 @@ bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _r
|
|||||||
|
|
||||||
bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs)
|
bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool {
|
return std::visit([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool {
|
||||||
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
||||||
return this->statementEqual(_lhsStmt, _rhsStmt);
|
return this->statementEqual(_lhsStmt, _rhsStmt);
|
||||||
}, _lhs, _rhs);
|
}, _lhs, _rhs);
|
||||||
|
@ -68,18 +68,18 @@ UnusedPruner::UnusedPruner(
|
|||||||
void UnusedPruner::operator()(Block& _block)
|
void UnusedPruner::operator()(Block& _block)
|
||||||
{
|
{
|
||||||
for (auto&& statement: _block.statements)
|
for (auto&& statement: _block.statements)
|
||||||
if (statement.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(statement))
|
||||||
{
|
{
|
||||||
FunctionDefinition& funDef = boost::get<FunctionDefinition>(statement);
|
FunctionDefinition& funDef = std::get<FunctionDefinition>(statement);
|
||||||
if (!used(funDef.name))
|
if (!used(funDef.name))
|
||||||
{
|
{
|
||||||
subtractReferences(ReferencesCounter::countReferences(funDef.body));
|
subtractReferences(ReferencesCounter::countReferences(funDef.body));
|
||||||
statement = Block{std::move(funDef.location), {}};
|
statement = Block{std::move(funDef.location), {}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (statement.type() == typeid(VariableDeclaration))
|
else if (holds_alternative<VariableDeclaration>(statement))
|
||||||
{
|
{
|
||||||
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(statement);
|
VariableDeclaration& varDecl = std::get<VariableDeclaration>(statement);
|
||||||
// Multi-variable declarations are special. We can only remove it
|
// Multi-variable declarations are special. We can only remove it
|
||||||
// if all variables are unused and the right-hand-side is either
|
// if all variables are unused and the right-hand-side is either
|
||||||
// movable or it returns a single value. In the latter case, we
|
// movable or it returns a single value. In the latter case, we
|
||||||
@ -108,9 +108,9 @@ void UnusedPruner::operator()(Block& _block)
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (statement.type() == typeid(ExpressionStatement))
|
else if (holds_alternative<ExpressionStatement>(statement))
|
||||||
{
|
{
|
||||||
ExpressionStatement& exprStmt = boost::get<ExpressionStatement>(statement);
|
ExpressionStatement& exprStmt = std::get<ExpressionStatement>(statement);
|
||||||
if (
|
if (
|
||||||
SideEffectsCollector(m_dialect, exprStmt.expression, m_functionSideEffects).
|
SideEffectsCollector(m_dialect, exprStmt.expression, m_functionSideEffects).
|
||||||
sideEffectFree(m_allowMSizeOptimization)
|
sideEffectFree(m_allowMSizeOptimization)
|
||||||
|
@ -51,5 +51,5 @@ void VarDeclInitializer::operator()(Block& _block)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
iterateReplacing(_block.statements, boost::apply_visitor(visitor));
|
iterateReplacing(_block.statements, [&](auto&& _statement) { return std::visit(visitor, _statement); });
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,8 @@ VarNameCleaner::VarNameCleaner(
|
|||||||
m_translatedNames{}
|
m_translatedNames{}
|
||||||
{
|
{
|
||||||
for (auto const& statement: _ast.statements)
|
for (auto const& statement: _ast.statements)
|
||||||
if (statement.type() == typeid(FunctionDefinition))
|
if (holds_alternative<FunctionDefinition>(statement))
|
||||||
m_blacklist.insert(boost::get<FunctionDefinition>(statement).name);
|
m_blacklist.insert(std::get<FunctionDefinition>(statement).name);
|
||||||
m_usedNames = m_blacklist;
|
m_usedNames = m_blacklist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ EVM_VERSIONS="homestead byzantium"
|
|||||||
|
|
||||||
if [ -z "$CI" ]
|
if [ -z "$CI" ]
|
||||||
then
|
then
|
||||||
EVM_VERSIONS+=" constantinople petersburg"
|
EVM_VERSIONS+=" constantinople petersburg istanbul"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
|
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
|
||||||
@ -91,9 +91,9 @@ do
|
|||||||
for vm in $EVM_VERSIONS
|
for vm in $EVM_VERSIONS
|
||||||
do
|
do
|
||||||
FORCE_ABIV2_RUNS="no"
|
FORCE_ABIV2_RUNS="no"
|
||||||
if [[ "$vm" == "constantinople" ]]
|
if [[ "$vm" == "istanbul" ]]
|
||||||
then
|
then
|
||||||
FORCE_ABIV2_RUNS="no yes" # run both in constantinople
|
FORCE_ABIV2_RUNS="no yes" # run both in istanbul
|
||||||
fi
|
fi
|
||||||
for abiv2 in $FORCE_ABIV2_RUNS
|
for abiv2 in $FORCE_ABIV2_RUNS
|
||||||
do
|
do
|
||||||
|
@ -32,13 +32,13 @@ namespace test
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static constexpr auto evmoneFilename = "evmone.dll";
|
static constexpr auto evmoneFilename = "evmone.dll";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-windows-amd64.zip";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-windows-amd64.zip";
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
static constexpr auto evmoneFilename = "libevmone.dylib";
|
static constexpr auto evmoneFilename = "libevmone.dylib";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-darwin-x86_64.tar.gz";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-darwin-x86_64.tar.gz";
|
||||||
#else
|
#else
|
||||||
static constexpr auto evmoneFilename = "libevmone.so";
|
static constexpr auto evmoneFilename = "libevmone.so";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.3.0/evmone-0.3.0-linux-x86_64.tar.gz";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@ evmc::VM* EVMHost::getVM(string const& _path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
|
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
|
||||||
m_vm(_vm)
|
m_vm(_vm),
|
||||||
|
m_evmVersion(_evmVersion)
|
||||||
{
|
{
|
||||||
if (!m_vm)
|
if (!m_vm)
|
||||||
{
|
{
|
||||||
@ -73,21 +74,21 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_evmVersion == langutil::EVMVersion::homestead())
|
if (_evmVersion == langutil::EVMVersion::homestead())
|
||||||
m_evmVersion = EVMC_HOMESTEAD;
|
m_evmRevision = EVMC_HOMESTEAD;
|
||||||
else if (_evmVersion == langutil::EVMVersion::tangerineWhistle())
|
else if (_evmVersion == langutil::EVMVersion::tangerineWhistle())
|
||||||
m_evmVersion = EVMC_TANGERINE_WHISTLE;
|
m_evmRevision = EVMC_TANGERINE_WHISTLE;
|
||||||
else if (_evmVersion == langutil::EVMVersion::spuriousDragon())
|
else if (_evmVersion == langutil::EVMVersion::spuriousDragon())
|
||||||
m_evmVersion = EVMC_SPURIOUS_DRAGON;
|
m_evmRevision = EVMC_SPURIOUS_DRAGON;
|
||||||
else if (_evmVersion == langutil::EVMVersion::byzantium())
|
else if (_evmVersion == langutil::EVMVersion::byzantium())
|
||||||
m_evmVersion = EVMC_BYZANTIUM;
|
m_evmRevision = EVMC_BYZANTIUM;
|
||||||
else if (_evmVersion == langutil::EVMVersion::constantinople())
|
else if (_evmVersion == langutil::EVMVersion::constantinople())
|
||||||
m_evmVersion = EVMC_CONSTANTINOPLE;
|
m_evmRevision = EVMC_CONSTANTINOPLE;
|
||||||
else if (_evmVersion == langutil::EVMVersion::istanbul())
|
else if (_evmVersion == langutil::EVMVersion::istanbul())
|
||||||
m_evmVersion = EVMC_ISTANBUL;
|
m_evmRevision = EVMC_ISTANBUL;
|
||||||
else if (_evmVersion == langutil::EVMVersion::berlin())
|
else if (_evmVersion == langutil::EVMVersion::berlin())
|
||||||
assertThrow(false, Exception, "Berlin is not supported yet.");
|
assertThrow(false, Exception, "Berlin is not supported yet.");
|
||||||
else //if (_evmVersion == langutil::EVMVersion::petersburg())
|
else //if (_evmVersion == langutil::EVMVersion::petersburg())
|
||||||
m_evmVersion = EVMC_PETERSBURG;
|
m_evmRevision = EVMC_PETERSBURG;
|
||||||
}
|
}
|
||||||
|
|
||||||
evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept
|
evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept
|
||||||
@ -146,7 +147,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
|
|||||||
{
|
{
|
||||||
message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas;
|
message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas;
|
||||||
for (size_t i = 0; i < message.input_size; ++i)
|
for (size_t i = 0; i < message.input_size; ++i)
|
||||||
message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas;
|
message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas(m_evmVersion);
|
||||||
if (message.gas < 0)
|
if (message.gas < 0)
|
||||||
{
|
{
|
||||||
evmc::result result({});
|
evmc::result result({});
|
||||||
@ -191,7 +192,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
|
|||||||
|
|
||||||
evmc::address currentAddress = m_currentAddress;
|
evmc::address currentAddress = m_currentAddress;
|
||||||
m_currentAddress = message.destination;
|
m_currentAddress = message.destination;
|
||||||
evmc::result result = m_vm->execute(*this, m_evmVersion, message, code.data(), code.size());
|
evmc::result result = m_vm->execute(*this, m_evmRevision, message, code.data(), code.size());
|
||||||
m_currentAddress = currentAddress;
|
m_currentAddress = currentAddress;
|
||||||
|
|
||||||
if (message.kind == EVMC_CREATE)
|
if (message.kind == EVMC_CREATE)
|
||||||
|
@ -180,7 +180,10 @@ private:
|
|||||||
static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
|
static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
|
||||||
|
|
||||||
evmc::VM* m_vm = nullptr;
|
evmc::VM* m_vm = nullptr;
|
||||||
evmc_revision m_evmVersion;
|
// EVM version requested by the testing tool
|
||||||
|
langutil::EVMVersion m_evmVersion;
|
||||||
|
// EVM version requested from EVMC (matches the above)
|
||||||
|
evmc_revision m_evmRevision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ target_sources(evmc INTERFACE
|
|||||||
${PROJECT_SOURCE_DIR}/test/evmc/evmc.h
|
${PROJECT_SOURCE_DIR}/test/evmc/evmc.h
|
||||||
${PROJECT_SOURCE_DIR}/test/evmc/evmc.hpp
|
${PROJECT_SOURCE_DIR}/test/evmc/evmc.hpp
|
||||||
${PROJECT_SOURCE_DIR}/test/evmc/helpers.h
|
${PROJECT_SOURCE_DIR}/test/evmc/helpers.h
|
||||||
${PROJECT_SOURCE_DIR}/test/evmc/helpers.hpp
|
|
||||||
${PROJECT_SOURCE_DIR}/test/evmc/utils.h
|
${PROJECT_SOURCE_DIR}/test/evmc/utils.h
|
||||||
)
|
)
|
||||||
target_include_directories(evmc INTERFACE ${PROJECT_SOURCE_DIR}/test/)
|
target_include_directories(evmc INTERFACE ${PROJECT_SOURCE_DIR}/test/)
|
||||||
|
3
test/evmc/README.md
Normal file
3
test/evmc/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# EVMC
|
||||||
|
|
||||||
|
This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.0.0](https://github.com/ethereum/evmc/releases/tag/v7.0.0).
|
@ -334,118 +334,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Host;
|
|
||||||
|
|
||||||
/// @copybrief evmc_vm
|
|
||||||
///
|
|
||||||
/// This is a RAII wrapper for evmc_vm and objects of this type
|
|
||||||
/// automatically destroys the VM instance.
|
|
||||||
class VM
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VM() noexcept = default;
|
|
||||||
|
|
||||||
/// Converting constructor from evmc_vm.
|
|
||||||
explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
|
|
||||||
|
|
||||||
/// Destructor responsible for automatically destroying the VM instance.
|
|
||||||
~VM() noexcept
|
|
||||||
{
|
|
||||||
if (m_instance)
|
|
||||||
m_instance->destroy(m_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
VM(const VM&) = delete;
|
|
||||||
VM& operator=(const VM&) = delete;
|
|
||||||
|
|
||||||
/// Move constructor.
|
|
||||||
VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
|
|
||||||
|
|
||||||
/// Move assignment operator.
|
|
||||||
VM& operator=(VM&& other) noexcept
|
|
||||||
{
|
|
||||||
this->~VM();
|
|
||||||
m_instance = other.m_instance;
|
|
||||||
other.m_instance = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The constructor that captures a VM instance and configures the instance
|
|
||||||
/// with the provided list of options.
|
|
||||||
inline VM(evmc_vm* vm,
|
|
||||||
std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
|
|
||||||
|
|
||||||
/// Checks if contains a valid pointer to the VM instance.
|
|
||||||
explicit operator bool() const noexcept { return m_instance != nullptr; }
|
|
||||||
|
|
||||||
/// Checks whenever the VM instance is ABI compatible with the current EVMC API.
|
|
||||||
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
|
|
||||||
|
|
||||||
/// @copydoc evmc_vm::name
|
|
||||||
char const* name() const noexcept { return m_instance->name; }
|
|
||||||
|
|
||||||
/// @copydoc evmc_vm::version
|
|
||||||
char const* version() const noexcept { return m_instance->version; }
|
|
||||||
|
|
||||||
/// @copydoc evmc::vm::get_capabilities
|
|
||||||
evmc_capabilities_flagset get_capabilities() const noexcept
|
|
||||||
{
|
|
||||||
return m_instance->get_capabilities(m_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @copydoc evmc_set_option()
|
|
||||||
evmc_set_option_result set_option(const char name[], const char value[]) noexcept
|
|
||||||
{
|
|
||||||
return evmc_set_option(m_instance, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @copydoc evmc_execute()
|
|
||||||
result execute(const evmc_host_interface& host,
|
|
||||||
evmc_host_context* ctx,
|
|
||||||
evmc_revision rev,
|
|
||||||
const evmc_message& msg,
|
|
||||||
const uint8_t* code,
|
|
||||||
size_t code_size) noexcept
|
|
||||||
{
|
|
||||||
return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenient variant of the VM::execute() that takes reference to evmc::Host class.
|
|
||||||
inline result execute(Host& host,
|
|
||||||
evmc_revision rev,
|
|
||||||
const evmc_message& msg,
|
|
||||||
const uint8_t* code,
|
|
||||||
size_t code_size) noexcept;
|
|
||||||
|
|
||||||
/// Executes code without the Host context.
|
|
||||||
///
|
|
||||||
/// The same as
|
|
||||||
/// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision,
|
|
||||||
/// const evmc_message&, const uint8_t*, size_t),
|
|
||||||
/// but without providing the Host context and interface.
|
|
||||||
/// This method is for experimental precompiles support where execution is
|
|
||||||
/// guaranteed not to require any Host access.
|
|
||||||
result execute(evmc_revision rev,
|
|
||||||
const evmc_message& msg,
|
|
||||||
const uint8_t* code,
|
|
||||||
size_t code_size) noexcept
|
|
||||||
{
|
|
||||||
return result{
|
|
||||||
m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
evmc_vm* m_instance = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline VM::VM(evmc_vm* vm,
|
|
||||||
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
|
|
||||||
: m_instance{vm}
|
|
||||||
{
|
|
||||||
for (const auto& option : options)
|
|
||||||
set_option(option.first, option.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// The EVMC Host interface
|
/// The EVMC Host interface
|
||||||
class HostInterface
|
class HostInterface
|
||||||
@ -514,8 +402,10 @@ public:
|
|||||||
HostContext() = default;
|
HostContext() = default;
|
||||||
|
|
||||||
/// Constructor from the EVMC Host primitives.
|
/// Constructor from the EVMC Host primitives.
|
||||||
HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept
|
/// @param interface The reference to the Host interface.
|
||||||
: host{interface}, context{ctx}
|
/// @param ctx The pointer to the Host context object. This parameter MAY be null.
|
||||||
|
HostContext(const evmc_host_interface& interface, evmc_host_context* ctx) noexcept
|
||||||
|
: host{&interface}, context{ctx}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool account_exists(const address& address) noexcept final
|
bool account_exists(const address& address) noexcept final
|
||||||
@ -596,6 +486,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Abstract class to be used by Host implementations.
|
/// Abstract class to be used by Host implementations.
|
||||||
///
|
///
|
||||||
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
|
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
|
||||||
@ -628,13 +519,118 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline result VM::execute(Host& host,
|
/// @copybrief evmc_vm
|
||||||
evmc_revision rev,
|
///
|
||||||
const evmc_message& msg,
|
/// This is a RAII wrapper for evmc_vm, and object of this type
|
||||||
const uint8_t* code,
|
/// automatically destroys the VM instance.
|
||||||
size_t code_size) noexcept
|
class VM
|
||||||
{
|
{
|
||||||
return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size);
|
public:
|
||||||
|
VM() noexcept = default;
|
||||||
|
|
||||||
|
/// Converting constructor from evmc_vm.
|
||||||
|
explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
|
||||||
|
|
||||||
|
/// Destructor responsible for automatically destroying the VM instance.
|
||||||
|
~VM() noexcept
|
||||||
|
{
|
||||||
|
if (m_instance)
|
||||||
|
m_instance->destroy(m_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
VM(const VM&) = delete;
|
||||||
|
VM& operator=(const VM&) = delete;
|
||||||
|
|
||||||
|
/// Move constructor.
|
||||||
|
VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
|
||||||
|
|
||||||
|
/// Move assignment operator.
|
||||||
|
VM& operator=(VM&& other) noexcept
|
||||||
|
{
|
||||||
|
this->~VM();
|
||||||
|
m_instance = other.m_instance;
|
||||||
|
other.m_instance = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The constructor that captures a VM instance and configures the instance
|
||||||
|
/// with the provided list of options.
|
||||||
|
inline VM(evmc_vm* vm,
|
||||||
|
std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
|
||||||
|
|
||||||
|
/// Checks if contains a valid pointer to the VM instance.
|
||||||
|
explicit operator bool() const noexcept { return m_instance != nullptr; }
|
||||||
|
|
||||||
|
/// Checks whenever the VM instance is ABI compatible with the current EVMC API.
|
||||||
|
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
|
||||||
|
|
||||||
|
/// @copydoc evmc_vm::name
|
||||||
|
char const* name() const noexcept { return m_instance->name; }
|
||||||
|
|
||||||
|
/// @copydoc evmc_vm::version
|
||||||
|
char const* version() const noexcept { return m_instance->version; }
|
||||||
|
|
||||||
|
/// @copydoc evmc::vm::get_capabilities
|
||||||
|
evmc_capabilities_flagset get_capabilities() const noexcept
|
||||||
|
{
|
||||||
|
return m_instance->get_capabilities(m_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc evmc_set_option()
|
||||||
|
evmc_set_option_result set_option(const char name[], const char value[]) noexcept
|
||||||
|
{
|
||||||
|
return evmc_set_option(m_instance, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc evmc_execute()
|
||||||
|
result execute(const evmc_host_interface& host,
|
||||||
|
evmc_host_context* ctx,
|
||||||
|
evmc_revision rev,
|
||||||
|
const evmc_message& msg,
|
||||||
|
const uint8_t* code,
|
||||||
|
size_t code_size) noexcept
|
||||||
|
{
|
||||||
|
return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenient variant of the VM::execute() that takes reference to evmc::Host class.
|
||||||
|
result execute(Host& host,
|
||||||
|
evmc_revision rev,
|
||||||
|
const evmc_message& msg,
|
||||||
|
const uint8_t* code,
|
||||||
|
size_t code_size) noexcept
|
||||||
|
{
|
||||||
|
return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes code without the Host context.
|
||||||
|
///
|
||||||
|
/// The same as
|
||||||
|
/// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision,
|
||||||
|
/// const evmc_message&, const uint8_t*, size_t),
|
||||||
|
/// but without providing the Host context and interface.
|
||||||
|
/// This method is for experimental precompiles support where execution is
|
||||||
|
/// guaranteed not to require any Host access.
|
||||||
|
result execute(evmc_revision rev,
|
||||||
|
const evmc_message& msg,
|
||||||
|
const uint8_t* code,
|
||||||
|
size_t code_size) noexcept
|
||||||
|
{
|
||||||
|
return result{
|
||||||
|
m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
evmc_vm* m_instance = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline VM::VM(evmc_vm* vm,
|
||||||
|
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
|
||||||
|
: m_instance{vm}
|
||||||
|
{
|
||||||
|
// This constructor is implemented outside of the class definition to workaround a doxygen bug.
|
||||||
|
for (const auto& option : options)
|
||||||
|
set_option(option.first, option.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/* EVMC: Ethereum Client-VM Connector API.
|
|
||||||
* Copyright 2018-2019 The EVMC Authors.
|
|
||||||
* Licensed under the Apache License, Version 2.0.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* A collection of helpers (overloaded operators) for using EVMC types effectively in C++.
|
|
||||||
*
|
|
||||||
* @addtogroup helpers
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <evmc/evmc.hpp>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
using evmc::is_zero;
|
|
||||||
|
|
||||||
/// The comparator for std::map<evmc_address, ...>.
|
|
||||||
EVMC_DEPRECATED
|
|
||||||
inline bool operator<(const evmc_address& a, const evmc_address& b)
|
|
||||||
{
|
|
||||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The comparator for std::map<evmc_bytes32, ...>.
|
|
||||||
EVMC_DEPRECATED
|
|
||||||
inline bool operator<(const evmc_bytes32& a, const evmc_bytes32& b)
|
|
||||||
{
|
|
||||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The comparator for equality.
|
|
||||||
EVMC_DEPRECATED
|
|
||||||
inline bool operator==(const evmc_address& a, const evmc_address& b)
|
|
||||||
{
|
|
||||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The comparator for equality.
|
|
||||||
EVMC_DEPRECATED
|
|
||||||
inline bool operator==(const evmc_bytes32& a, const evmc_bytes32& b)
|
|
||||||
{
|
|
||||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parameters for the fnv1a hash function, specialized by the hash result size (size_t).
|
|
||||||
///
|
|
||||||
/// The values for the matching size are taken from
|
|
||||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters.
|
|
||||||
///
|
|
||||||
/// @tparam size The size of the hash result (size_t).
|
|
||||||
template <size_t size>
|
|
||||||
struct fnv1_params
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parameters for the fnv1a hash function, specialized for the hash result of 4 bytes.
|
|
||||||
template <>
|
|
||||||
struct fnv1_params<4>
|
|
||||||
{
|
|
||||||
static constexpr auto prime = 0x1000193; ///< The FNV prime.
|
|
||||||
static constexpr auto offset_basis = 0x811c9dc5; ///< The FNV offset basis.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parameters for the fnv1a hash function, specialized for the hash result of 8 bytes.
|
|
||||||
template <>
|
|
||||||
struct fnv1_params<8>
|
|
||||||
{
|
|
||||||
static constexpr auto prime = 0x100000001b3; ///< The FNV prime.
|
|
||||||
static constexpr auto offset_basis = 0xcbf29ce484222325; ///< The FNV offset basis.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// FNV1a hash function.
|
|
||||||
inline size_t fnv1a(const uint8_t* ptr, size_t len) noexcept
|
|
||||||
{
|
|
||||||
using params = fnv1_params<sizeof(size_t)>;
|
|
||||||
|
|
||||||
auto ret = size_t{params::offset_basis};
|
|
||||||
for (size_t i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
ret ^= ptr[i];
|
|
||||||
ret *= params::prime;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
/// Hash operator template specialization for evmc_address needed for unordered containers.
|
|
||||||
template <>
|
|
||||||
struct EVMC_DEPRECATED hash<evmc_address>
|
|
||||||
{
|
|
||||||
/// Hash operator using FNV1a.
|
|
||||||
size_t operator()(const evmc_address& s) const noexcept
|
|
||||||
{
|
|
||||||
return fnv1a(s.bytes, sizeof(s.bytes));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Hash operator template needed for std::unordered_set and others using hashes.
|
|
||||||
template <>
|
|
||||||
struct EVMC_DEPRECATED hash<evmc_bytes32>
|
|
||||||
{
|
|
||||||
/// Hash operator using FNV1a.
|
|
||||||
size_t operator()(const evmc_bytes32& s) const noexcept
|
|
||||||
{
|
|
||||||
return fnv1a(s.bytes, sizeof(s.bytes));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
|
||||||
|
|
||||||
/** @} */
|
|
@ -246,7 +246,7 @@ function truffle_run_test
|
|||||||
for optimize in "${optimizer_settings[@]}"
|
for optimize in "${optimizer_settings[@]}"
|
||||||
do
|
do
|
||||||
clean
|
clean
|
||||||
force_solc_settings "$CONFIG" "$optimize" "petersburg"
|
force_solc_settings "$CONFIG" "$optimize" "istanbul"
|
||||||
# Force ABIEncoderV2 in the last step. Has to be the last because code is modified.
|
# Force ABIEncoderV2 in the last step. Has to be the last because code is modified.
|
||||||
if [ "$FORCE_ABIv2" = true ]; then
|
if [ "$FORCE_ABIv2" = true ]; then
|
||||||
[[ "$optimize" =~ yul ]] && force_abi_v2
|
[[ "$optimize" =~ yul ]] && force_abi_v2
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <test/libsolidity/SolidityExecutionFramework.h>
|
#include <test/libsolidity/SolidityExecutionFramework.h>
|
||||||
|
#include <liblangutil/EVMVersion.h>
|
||||||
#include <libdevcore/IpfsHash.h>
|
#include <libdevcore/IpfsHash.h>
|
||||||
#include <libevmasm/GasMeter.h>
|
#include <libevmasm/GasMeter.h>
|
||||||
|
|
||||||
@ -37,10 +38,10 @@ namespace solidity
|
|||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
|
|
||||||
#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt) \
|
#define CHECK_DEPLOY_GAS(_gasNoOpt, _gasOpt, _evmVersion) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
u256 ipfsCost = GasMeter::dataGas(dev::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true); \
|
u256 ipfsCost = GasMeter::dataGas(dev::ipfsHash(m_compiler.metadata(m_compiler.lastContractName())), true, _evmVersion); \
|
||||||
u256 gasOpt{_gasOpt}; \
|
u256 gasOpt{_gasOpt}; \
|
||||||
u256 gasNoOpt{_gasNoOpt}; \
|
u256 gasNoOpt{_gasNoOpt}; \
|
||||||
u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \
|
u256 gas = m_optimiserSettings == OptimiserSettings::minimal() ? gasNoOpt : gasOpt; \
|
||||||
@ -95,34 +96,61 @@ BOOST_AUTO_TEST_CASE(string_storage)
|
|||||||
m_compiler.overwriteReleaseFlag(true);
|
m_compiler.overwriteReleaseFlag(true);
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
if (Options::get().evmVersion() <= EVMVersion::byzantium())
|
auto evmVersion = dev::test::Options::get().evmVersion();
|
||||||
CHECK_DEPLOY_GAS(134145, 130831);
|
|
||||||
|
if (evmVersion <= EVMVersion::byzantium())
|
||||||
|
CHECK_DEPLOY_GAS(134145, 130831, evmVersion);
|
||||||
// This is only correct on >=Constantinople.
|
// This is only correct on >=Constantinople.
|
||||||
else if (Options::get().useABIEncoderV2)
|
else if (Options::get().useABIEncoderV2)
|
||||||
{
|
{
|
||||||
if (Options::get().optimizeYul)
|
if (Options::get().optimizeYul)
|
||||||
CHECK_DEPLOY_GAS(127785, 127721);
|
{
|
||||||
|
// Costs with 0 are cases which cannot be triggered in tests.
|
||||||
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
|
CHECK_DEPLOY_GAS(0, 127721, evmVersion);
|
||||||
|
else
|
||||||
|
CHECK_DEPLOY_GAS(0, 113993, evmVersion);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
CHECK_DEPLOY_GAS(151587, 135371);
|
{
|
||||||
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
|
CHECK_DEPLOY_GAS(151523, 135371, evmVersion);
|
||||||
|
else
|
||||||
|
CHECK_DEPLOY_GAS(134883, 120083, evmVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (evmVersion < EVMVersion::istanbul())
|
||||||
|
CHECK_DEPLOY_GAS(126929, 119659, evmVersion);
|
||||||
else
|
else
|
||||||
CHECK_DEPLOY_GAS(126929, 119659);
|
CHECK_DEPLOY_GAS(114345, 107335, evmVersion);
|
||||||
|
|
||||||
if (Options::get().evmVersion() >= EVMVersion::byzantium())
|
if (evmVersion >= EVMVersion::byzantium())
|
||||||
{
|
{
|
||||||
callContractFunction("f()");
|
callContractFunction("f()");
|
||||||
if (Options::get().evmVersion() == EVMVersion::byzantium())
|
if (evmVersion == EVMVersion::byzantium())
|
||||||
CHECK_GAS(21551, 21526, 20);
|
CHECK_GAS(21545, 21526, 20);
|
||||||
// This is only correct on >=Constantinople.
|
// This is only correct on >=Constantinople.
|
||||||
else if (Options::get().useABIEncoderV2)
|
else if (Options::get().useABIEncoderV2)
|
||||||
{
|
{
|
||||||
if (Options::get().optimizeYul)
|
if (Options::get().optimizeYul)
|
||||||
CHECK_GAS(21713, 21567, 20);
|
{
|
||||||
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
|
CHECK_GAS(0, 21567, 20);
|
||||||
|
else
|
||||||
|
CHECK_GAS(0, 21351, 20);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
CHECK_GAS(21713, 21635, 20);
|
{
|
||||||
|
if (evmVersion < EVMVersion::istanbul())
|
||||||
|
CHECK_GAS(21707, 21635, 20);
|
||||||
|
else
|
||||||
|
CHECK_GAS(21499, 21431, 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (evmVersion < EVMVersion::istanbul())
|
||||||
CHECK_GAS(21546, 21526, 20);
|
CHECK_GAS(21546, 21526, 20);
|
||||||
|
else
|
||||||
|
CHECK_GAS(21332, 21322, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +114,10 @@ public:
|
|||||||
|
|
||||||
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
|
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
|
||||||
{
|
{
|
||||||
|
auto evmVersion = dev::test::Options::get().evmVersion();
|
||||||
GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas;
|
GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas;
|
||||||
for (auto i: _data)
|
for (auto i: _data)
|
||||||
gas += i != 0 ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas;
|
gas += i != 0 ? GasCosts::txDataNonZeroGas(evmVersion) : GasCosts::txDataZeroGas;
|
||||||
return gas;
|
return gas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
test/libsolidity/semanticTests/inlineAssembly/chainid.sol
Normal file
12
test/libsolidity/semanticTests/inlineAssembly/chainid.sol
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public returns (uint id) {
|
||||||
|
assembly {
|
||||||
|
id := chainid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >=istanbul
|
||||||
|
// ----
|
||||||
|
// f() -> 1
|
@ -0,0 +1,12 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public payable returns (uint ret) {
|
||||||
|
assembly {
|
||||||
|
ret := selfbalance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=istanbul
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(), 254 ether -> 254
|
@ -0,0 +1,15 @@
|
|||||||
|
contract S
|
||||||
|
{
|
||||||
|
int o;
|
||||||
|
function foo() public returns (int) { return o = 3; }
|
||||||
|
}
|
||||||
|
|
||||||
|
contract B is S
|
||||||
|
{
|
||||||
|
function fii() public
|
||||||
|
{
|
||||||
|
o = S(super).foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (129-137): Explicit type conversion not allowed from "contract super B" to "contract S".
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user