aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md16
-rw-r--r--Changelog.md1
-rw-r--r--docs/contributing.rst2
-rw-r--r--docs/solidity-by-example.rst2
-rw-r--r--docs/types.rst3
-rw-r--r--libdevcore/Common.h8
-rw-r--r--libdevcore/CommonData.cpp2
-rw-r--r--libdevcore/CommonData.h6
-rw-r--r--libdevcore/FixedHash.h16
-rw-r--r--libevmasm/Assembly.cpp26
-rw-r--r--libevmasm/AssemblyItem.h2
-rw-r--r--libevmasm/Instruction.h8
-rw-r--r--libevmasm/SimplificationRules.cpp6
-rw-r--r--liblll/CodeFragment.cpp2
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp8
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp2
-rw-r--r--libsolidity/ast/Types.cpp3
-rw-r--r--libsolidity/codegen/CompilerContext.cpp5
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp58
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp22
-rw-r--r--libsolidity/inlineasm/AsmData.h19
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp20
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp22
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h4
-rw-r--r--libsolidity/inlineasm/AsmScope.cpp10
-rw-r--r--libsolidity/inlineasm/AsmScope.h18
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.cpp10
-rw-r--r--libsolidity/interface/Version.cpp6
-rw-r--r--libyul/ASTDataForward.h1
-rw-r--r--libyul/Exceptions.h5
-rw-r--r--libyul/YulString.h96
-rw-r--r--libyul/backends/evm/EVMAssembly.cpp14
-rw-r--r--libyul/backends/evm/EVMCodeTransform.cpp12
-rw-r--r--libyul/backends/evm/EVMCodeTransform.h2
-rw-r--r--libyul/optimiser/ASTCopier.cpp4
-rw-r--r--libyul/optimiser/ASTCopier.h4
-rw-r--r--libyul/optimiser/ASTWalker.h1
-rw-r--r--libyul/optimiser/CommonSubexpressionEliminator.cpp4
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.cpp26
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.h17
-rw-r--r--libyul/optimiser/Disambiguator.cpp2
-rw-r--r--libyul/optimiser/Disambiguator.h8
-rw-r--r--libyul/optimiser/ExpressionInliner.cpp2
-rw-r--r--libyul/optimiser/ExpressionInliner.h6
-rw-r--r--libyul/optimiser/ExpressionJoiner.cpp30
-rw-r--r--libyul/optimiser/ExpressionJoiner.h26
-rw-r--r--libyul/optimiser/ExpressionSimplifier.h4
-rw-r--r--libyul/optimiser/ExpressionSplitter.cpp4
-rw-r--r--libyul/optimiser/FullInliner.cpp18
-rw-r--r--libyul/optimiser/FullInliner.h28
-rw-r--r--libyul/optimiser/InlinableExpressionFunctionFinder.cpp4
-rw-r--r--libyul/optimiser/InlinableExpressionFunctionFinder.h8
-rw-r--r--libyul/optimiser/MainFunction.cpp4
-rw-r--r--libyul/optimiser/NameCollector.cpp14
-rw-r--r--libyul/optimiser/NameCollector.h17
-rw-r--r--libyul/optimiser/NameDispenser.cpp16
-rw-r--r--libyul/optimiser/NameDispenser.h11
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.cpp6
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.h15
-rw-r--r--libyul/optimiser/Rematerialiser.cpp2
-rw-r--r--libyul/optimiser/Rematerialiser.h4
-rw-r--r--libyul/optimiser/SSATransform.cpp8
-rw-r--r--libyul/optimiser/SSATransform.h6
-rw-r--r--libyul/optimiser/SSAValueTracker.cpp2
-rw-r--r--libyul/optimiser/SSAValueTracker.h9
-rw-r--r--libyul/optimiser/Semantics.cpp2
-rw-r--r--libyul/optimiser/Semantics.h6
-rw-r--r--libyul/optimiser/SimplificationRules.cpp20
-rw-r--r--libyul/optimiser/SimplificationRules.h4
-rw-r--r--libyul/optimiser/Substitution.cpp2
-rw-r--r--libyul/optimiser/Substitution.h8
-rw-r--r--libyul/optimiser/Suite.cpp4
-rw-r--r--libyul/optimiser/Suite.h6
-rw-r--r--libyul/optimiser/SyntacticalEquality.cpp1
-rw-r--r--libyul/optimiser/UnusedPruner.cpp8
-rw-r--r--libyul/optimiser/UnusedPruner.h12
-rw-r--r--libyul/optimiser/VarDeclPropagator.cpp129
-rw-r--r--libyul/optimiser/VarDeclPropagator.h63
-rwxr-xr-xscripts/release_ppa.sh2
-rw-r--r--test/ExecutionFramework.h4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp76
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp228
-rw-r--r--test/libsolidity/SolidityTypes.cpp2
-rw-r--r--test/libsolidity/syntaxTests/array/length/parameter_too_large.sol5
-rw-r--r--test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim.sol11
-rw-r--r--test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim_ABIv2.sol10
-rw-r--r--test/libyul/Inliner.cpp8
-rw-r--r--test/libyul/YulOptimizerTest.cpp6
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul17
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul13
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul11
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul10
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul9
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul11
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul12
-rw-r--r--test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul16
96 files changed, 949 insertions, 514 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 9734fe81..9fdbf158 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -5,6 +5,14 @@ Please review the [guidelines for contributing](http://solidity.readthedocs.io/e
Please also note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
-->
+### Description
+
+<!--
+Please explain the changes you made here.
+
+Thank you for your help!
+-->
+
### Checklist
- [ ] Code compiles correctly
- [ ] All tests are passing
@@ -12,11 +20,3 @@ Please also note that this project is released with a [Contributor Code of Condu
- [ ] README / documentation was extended, if necessary
- [ ] Changelog entry (if change is visible to the user)
- [ ] Used meaningful commit messages
-
-### Description
-
-<!--
-Please explain the changes you made here.
-
-Thank you for your help!
---> \ No newline at end of file
diff --git a/Changelog.md b/Changelog.md
index 5bf194e4..ff95a89a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -128,6 +128,7 @@ Bugfixes:
* Type Checker: Fix freeze for negative fixed-point literals very close to ``0``, such as ``-1e-100``.
* Type Checker: Dynamic types as key for public mappings return error instead of assertion fail.
* Type Checker: Fix internal error when array index value is too large.
+ * Type Checker: Fix internal error when fixed-size array is too large to be encoded.
* Type Checker: Fix internal error for array type conversions.
* Type Checker: Fix internal error when array index is not an unsigned.
* Type System: Allow arbitrary exponents for literals with a mantissa of zero.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index edd7361e..e626e5c0 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -16,7 +16,7 @@ In particular, we need help in the following areas:
<https://gitter.im/ethereum/solidity>`_
* Fixing and responding to `Solidity's GitHub issues
<https://github.com/ethereum/solidity/issues>`_, especially those tagged as
- `up-for-grabs <https://github.com/ethereum/solidity/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs>`_ which are
+ `good first issue <https://github.com/ethereum/solidity/labels/good%20first%20issue>`_ which are
meant as introductory issues for external contributors.
Please note that this project is released with a `Contributor Code of Conduct <https://raw.githubusercontent.com/ethereum/solidity/develop/CODE_OF_CONDUCT.md>`_. By participating in this project - in the issues, pull requests, or Gitter channels - you agree to abide by its terms.
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index f71f1e23..752e8641 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -877,7 +877,7 @@ two parties (Alice and Bob). Using it involves three steps:
2. Alice signs messages that specify how much of that Ether is owed to the recipient. This step is repeated for each payment.
3. Bob "closes" the payment channel, withdrawing their portion of the Ether and sending the remainder back to the sender.
-Not ethat only steps 1 and 3 require Ethereum transactions, step 2 means that
+Note that only steps 1 and 3 require Ethereum transactions, step 2 means that
the sender transmits a cryptographically signed message to the recipient via off chain ways (e.g. email).
This means only two transactions are required to support any number of transfers.
diff --git a/docs/types.rst b/docs/types.rst
index bd5d1734..34b94b88 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -1225,7 +1225,6 @@ is possible if it
makes sense semantically and no information is lost: ``uint8`` is convertible to
``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256``
(because ``uint256`` cannot hold e.g. ``-1``).
-Any integer type that can be converted to ``uint160`` can also be converted to ``address``.
For more details, please consult the sections about the types themselves.
@@ -1335,4 +1334,4 @@ Addresses
As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum
test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type.
-Explicit conversions from ``bytes20`` or any integer type to ``address`` results in ``address payable``. \ No newline at end of file
+Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``.
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index 0363d9a2..6208424e 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -64,15 +64,13 @@
#include <functional>
#include <string>
-using byte = uint8_t;
-
namespace dev
{
// Binary data types.
-using bytes = std::vector<byte>;
-using bytesRef = vector_ref<byte>;
-using bytesConstRef = vector_ref<byte const>;
+using bytes = std::vector<uint8_t>;
+using bytesRef = vector_ref<uint8_t>;
+using bytesConstRef = vector_ref<uint8_t const>;
// Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp
index fa1a5353..91c60ffe 100644
--- a/libdevcore/CommonData.cpp
+++ b/libdevcore/CommonData.cpp
@@ -64,7 +64,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
int h = fromHex(_s[i], WhenError::DontThrow);
int l = fromHex(_s[i + 1], WhenError::DontThrow);
if (h != -1 && l != -1)
- ret.push_back((byte)(h * 16 + l));
+ ret.push_back((uint8_t)(h * 16 + l));
else if (_throw == WhenError::Throw)
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index 0782fabc..fedd3af2 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -88,7 +88,7 @@ inline std::string asString(bytesConstRef _b)
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{
- return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
+ return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size()));
}
// Big-endian to/from host endian conversion functions.
@@ -117,7 +117,7 @@ inline T fromBigEndian(_In const& _bytes)
{
T ret = (T)0;
for (auto i: _bytes)
- ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i);
+ ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<typename _In::value_type>::type)i);
return ret;
}
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
@@ -135,7 +135,7 @@ inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
toBigEndian(_val, ret);
return ret;
}
-inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
+inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0)
{
return (_min || _val) ? bytes{ _val } : bytes{};
}
diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h
index cd6e1da1..24b89840 100644
--- a/libdevcore/FixedHash.h
+++ b/libdevcore/FixedHash.h
@@ -79,7 +79,7 @@ public:
operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash.
- explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); }
+ explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; }); }
// The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
@@ -90,9 +90,9 @@ public:
FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; }
/// @returns a particular byte from the hash.
- byte& operator[](unsigned _i) { return m_data[_i]; }
+ uint8_t& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
- byte operator[](unsigned _i) const { return m_data[_i]; }
+ uint8_t operator[](unsigned _i) const { return m_data[_i]; }
/// @returns the hash as a user-readable hex string.
std::string hex() const { return toHex(ref()); }
@@ -104,19 +104,19 @@ public:
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data.
- byte* data() { return m_data.data(); }
+ uint8_t* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data.
- byte const* data() const { return m_data.data(); }
+ uint8_t const* data() const { return m_data.data(); }
/// @returns a copy of the object's data as a byte vector.
bytes asBytes() const { return bytes(data(), data() + N); }
/// @returns a mutable reference to the object's data as an STL array.
- std::array<byte, N>& asArray() { return m_data; }
+ std::array<uint8_t, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array.
- std::array<byte, N> const& asArray() const { return m_data; }
+ std::array<uint8_t, N> const& asArray() const { return m_data; }
/// Returns the index of the first bit set to one, or size() * 8 if no bits are set.
inline unsigned firstBitSet() const
@@ -137,7 +137,7 @@ public:
void clear() { m_data.fill(0); }
private:
- std::array<byte, N> m_data; ///< The binary data.
+ std::array<uint8_t, N> m_data; ///< The binary data.
};
/// Stream I/O for the FixedHash class.
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index c2eaa1ca..e63194a0 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -525,14 +525,14 @@ LinkerObject const& Assembly::assemble() const
multimap<size_t, size_t> subRef;
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
unsigned bytesPerTag = dev::bytesRequired(bytesRequiredForCode);
- byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
+ uint8_t tagPush = (uint8_t)Instruction::PUSH1 - 1 + bytesPerTag;
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + m_auxiliaryData.size();
for (auto const& sub: m_subs)
bytesRequiredIncludingData += sub->assemble().bytecode.size();
unsigned bytesPerDataRef = dev::bytesRequired(bytesRequiredIncludingData);
- byte dataRefPush = (byte)Instruction::PUSH1 - 1 + bytesPerDataRef;
+ uint8_t dataRefPush = (uint8_t)Instruction::PUSH1 - 1 + bytesPerDataRef;
ret.bytecode.reserve(bytesRequiredIncludingData);
for (AssemblyItem const& i: m_items)
@@ -544,25 +544,25 @@ LinkerObject const& Assembly::assemble() const
switch (i.type())
{
case Operation:
- ret.bytecode.push_back((byte)i.instruction());
+ ret.bytecode.push_back((uint8_t)i.instruction());
break;
case PushString:
{
- ret.bytecode.push_back((byte)Instruction::PUSH32);
+ ret.bytecode.push_back((uint8_t)Instruction::PUSH32);
unsigned ii = 0;
for (auto j: m_strings.at((h256)i.data()))
if (++ii > 32)
break;
else
- ret.bytecode.push_back((byte)j);
+ ret.bytecode.push_back((uint8_t)j);
while (ii++ < 32)
ret.bytecode.push_back(0);
break;
}
case Push:
{
- byte b = max<unsigned>(1, dev::bytesRequired(i.data()));
- ret.bytecode.push_back((byte)Instruction::PUSH1 - 1 + b);
+ uint8_t b = max<unsigned>(1, dev::bytesRequired(i.data()));
+ ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b);
ret.bytecode.resize(ret.bytecode.size() + b);
bytesRef byr(&ret.bytecode.back() + 1 - b, b);
toBigEndian(i.data(), byr);
@@ -589,8 +589,8 @@ LinkerObject const& Assembly::assemble() const
{
auto s = m_subs.at(size_t(i.data()))->assemble().bytecode.size();
i.setPushedValue(u256(s));
- byte b = max<unsigned>(1, dev::bytesRequired(s));
- ret.bytecode.push_back((byte)Instruction::PUSH1 - 1 + b);
+ uint8_t b = max<unsigned>(1, dev::bytesRequired(s));
+ ret.bytecode.push_back((uint8_t)Instruction::PUSH1 - 1 + b);
ret.bytecode.resize(ret.bytecode.size() + b);
bytesRef byr(&ret.bytecode.back() + 1 - b, b);
toBigEndian(s, byr);
@@ -604,12 +604,12 @@ LinkerObject const& Assembly::assemble() const
break;
}
case PushLibraryAddress:
- ret.bytecode.push_back(byte(Instruction::PUSH20));
+ ret.bytecode.push_back(uint8_t(Instruction::PUSH20));
ret.linkReferences[ret.bytecode.size()] = m_libraries.at(i.data());
ret.bytecode.resize(ret.bytecode.size() + 20);
break;
case PushDeployTimeAddress:
- ret.bytecode.push_back(byte(Instruction::PUSH20));
+ ret.bytecode.push_back(uint8_t(Instruction::PUSH20));
ret.bytecode.resize(ret.bytecode.size() + 20);
break;
case Tag:
@@ -618,7 +618,7 @@ LinkerObject const& Assembly::assemble() const
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
assertThrow(m_tagPositionsInBytecode[size_t(i.data())] == size_t(-1), AssemblyException, "Duplicate tag position.");
m_tagPositionsInBytecode[size_t(i.data())] = ret.bytecode.size();
- ret.bytecode.push_back((byte)Instruction::JUMPDEST);
+ ret.bytecode.push_back((uint8_t)Instruction::JUMPDEST);
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
@@ -627,7 +627,7 @@ LinkerObject const& Assembly::assemble() const
if (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty())
// Append an INVALID here to help tests find miscompilation.
- ret.bytecode.push_back(byte(Instruction::INVALID));
+ ret.bytecode.push_back(uint8_t(Instruction::INVALID));
for (size_t i = 0; i < m_subs.size(); ++i)
{
diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h
index 5319a2b6..6187e18f 100644
--- a/libevmasm/AssemblyItem.h
+++ b/libevmasm/AssemblyItem.h
@@ -69,7 +69,7 @@ public:
m_location(_location)
{
if (m_type == Operation)
- m_instruction = Instruction(byte(_data));
+ m_instruction = Instruction(uint8_t(_data));
else
m_data = std::make_shared<u256>(_data);
}
diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h
index 63424eeb..539a83b0 100644
--- a/libevmasm/Instruction.h
+++ b/libevmasm/Instruction.h
@@ -228,25 +228,25 @@ inline bool isLogInstruction(Instruction _inst)
/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
- return (byte)_inst - unsigned(Instruction::PUSH1) + 1;
+ return (uint8_t)_inst - unsigned(Instruction::PUSH1) + 1;
}
/// @returns the number of DUP Instruction _inst
inline unsigned getDupNumber(Instruction _inst)
{
- return (byte)_inst - unsigned(Instruction::DUP1) + 1;
+ return (uint8_t)_inst - unsigned(Instruction::DUP1) + 1;
}
/// @returns the number of SWAP Instruction _inst
inline unsigned getSwapNumber(Instruction _inst)
{
- return (byte)_inst - unsigned(Instruction::SWAP1) + 1;
+ return (uint8_t)_inst - unsigned(Instruction::SWAP1) + 1;
}
/// @returns the number of LOG Instruction _inst
inline unsigned getLogNumber(Instruction _inst)
{
- return (byte)_inst - unsigned(Instruction::LOG0);
+ return (uint8_t)_inst - unsigned(Instruction::LOG0);
}
/// @returns the PUSH<_number> instruction
diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp
index ba13a611..120d1787 100644
--- a/libevmasm/SimplificationRules.cpp
+++ b/libevmasm/SimplificationRules.cpp
@@ -48,7 +48,7 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch(
resetMatchGroups();
assertThrow(_expr.item, OptimizerException, "");
- for (auto const& rule: m_rules[byte(_expr.item->instruction())])
+ for (auto const& rule: m_rules[uint8_t(_expr.item->instruction())])
{
if (rule.pattern.matches(_expr, _classes))
return &rule;
@@ -59,7 +59,7 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch(
bool Rules::isInitialized() const
{
- return !m_rules[byte(Instruction::ADD)].empty();
+ return !m_rules[uint8_t(Instruction::ADD)].empty();
}
void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules)
@@ -70,7 +70,7 @@ void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules)
void Rules::addRule(SimplificationRule<Pattern> const& _rule)
{
- m_rules[byte(_rule.pattern.instruction())].push_back(_rule);
+ m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule);
}
Rules::Rules()
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 0aef05a9..85480119 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -348,7 +348,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
else if (i.which() == sp::utree_type::string_type)
{
auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
- data.insert(data.end(), (byte const *)sr.begin(), (byte const*)sr.end());
+ data.insert(data.end(), (uint8_t const *)sr.begin(), (uint8_t const*)sr.end());
}
else if (i.which() == sp::utree_type::any_type)
{
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index f62d9c3b..2adc8e77 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -271,16 +271,16 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
ErrorReporter errorsIgnored(errors);
yul::ExternalIdentifierAccess::Resolver resolver =
[&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
- auto declarations = m_resolver.nameFromCurrentScope(_identifier.name);
- bool isSlot = boost::algorithm::ends_with(_identifier.name, "_slot");
- bool isOffset = boost::algorithm::ends_with(_identifier.name, "_offset");
+ auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
+ bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
+ bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
if (isSlot || isOffset)
{
// special mode to access storage variables
if (!declarations.empty())
// the special identifier exists itself, we should not allow that.
return size_t(-1);
- string realName = _identifier.name.substr(0, _identifier.name.size() - (
+ string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - (
isSlot ?
string("_slot").size() :
string("_offset").size()
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 569e5b0e..2d26ce8a 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -459,7 +459,7 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node)
if (it.first)
{
Json::Value tuple(Json::objectValue);
- tuple[it.first->name] = inlineAssemblyIdentifierToJson(it);
+ tuple[it.first->name.str()] = inlineAssemblyIdentifierToJson(it);
externalReferences.append(tuple);
}
}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 301687b4..d5d11478 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1698,6 +1698,9 @@ bool ArrayType::operator==(Type const& _other) const
bool ArrayType::validForCalldata() const
{
+ if (auto arrayBaseType = dynamic_cast<ArrayType const*>(baseType().get()))
+ if (!arrayBaseType->validForCalldata())
+ return false;
return unlimitedCalldataEncodedSize(true) <= numeric_limits<unsigned>::max();
}
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 210b613d..6e14d68a 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -32,6 +32,7 @@
#include <libsolidity/inlineasm/AsmCodeGen.h>
#include <libsolidity/inlineasm/AsmAnalysis.h>
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
+#include <libyul/YulString.h>
#include <boost/algorithm/string/replace.hpp>
@@ -326,7 +327,7 @@ void CompilerContext::appendInlineAssembly(
bool
)
{
- auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
+ auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
return it == _localVariables.end() ? size_t(-1) : 1;
};
identifierAccess.generateCode = [&](
@@ -335,7 +336,7 @@ void CompilerContext::appendInlineAssembly(
yul::AbstractAssembly& _assembly
)
{
- auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
+ auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
solAssert(it != _localVariables.end(), "");
int stackDepth = _localVariables.end() - it;
int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth;
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 2bdf88e3..d89d023e 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -142,9 +142,13 @@ void CompilerUtils::storeInMemory(unsigned _offset)
void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries)
{
+ // process special types (Reference, StringLiteral, Function)
if (auto ref = dynamic_cast<ReferenceType const*>(&_type))
{
- solUnimplementedAssert(ref->location() == DataLocation::Memory, "Only in-memory reference type can be stored.");
+ solUnimplementedAssert(
+ ref->location() == DataLocation::Memory,
+ "Only in-memory reference type can be stored."
+ );
storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
}
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
@@ -166,18 +170,18 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
m_context << Instruction::DUP2 << Instruction::MSTORE;
m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD;
}
- else
+ else if (_type.isValueType())
{
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
- if (numBytes > 0)
- {
- solUnimplementedAssert(
- _type.sizeOnStack() == 1,
- "Memory store of types with stack size != 1 not implemented."
- );
- m_context << Instruction::DUP2 << Instruction::MSTORE;
- m_context << u256(numBytes) << Instruction::ADD;
- }
+ m_context << Instruction::DUP2 << Instruction::MSTORE;
+ m_context << u256(numBytes) << Instruction::ADD;
+ }
+ else // Should never happen
+ {
+ solAssert(
+ false,
+ "Memory store of type " + _type.toString(true) + " not allowed."
+ );
}
}
@@ -1266,18 +1270,30 @@ void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords)
{
+ solAssert(
+ _type.sizeOnStack() == 1,
+ "Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")."
+ );
+
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
+
+ solAssert(
+ numBytes > 0,
+ "Memory store of 0 bytes requested (Type: " + _type.toString(true) + ")."
+ );
+
+ solAssert(
+ numBytes <= 32,
+ "Memory store of more than 32 bytes requested (Type: " + _type.toString(true) + ")."
+ );
+
bool leftAligned = _type.category() == Type::Category::FixedBytes;
- if (numBytes == 0)
- m_context << Instruction::POP;
- else
- {
- solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested.");
- convertType(_type, _type, true);
- if (numBytes != 32 && !leftAligned && !_padToWords)
- // shift the value accordingly before storing
- leftShiftNumberOnStack((32 - numBytes) * 8);
- }
+
+ convertType(_type, _type, true);
+ if (numBytes != 32 && !leftAligned && !_padToWords)
+ // shift the value accordingly before storing
+ leftShiftNumberOnStack((32 - numBytes) * 8);
+
return numBytes;
}
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index 04b5d1a8..ac019c06 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -79,17 +79,17 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
{
- expectValidType(_literal.type, _literal.location);
+ expectValidType(_literal.type.str(), _literal.location);
++m_stackHeight;
- if (_literal.kind == assembly::LiteralKind::String && _literal.value.size() > 32)
+ if (_literal.kind == assembly::LiteralKind::String && _literal.value.str().size() > 32)
{
m_errorReporter.typeError(
_literal.location,
- "String literal too long (" + to_string(_literal.value.size()) + " > 32)"
+ "String literal too long (" + to_string(_literal.value.str().size()) + " > 32)"
);
return false;
}
- else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value) > u256(-1))
+ else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value.str()) > u256(-1))
{
m_errorReporter.typeError(
_literal.location,
@@ -100,7 +100,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
else if (_literal.kind == assembly::LiteralKind::Boolean)
{
solAssert(m_flavour == AsmFlavour::Yul, "");
- solAssert(_literal.value == "true" || _literal.value == "false", "");
+ solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, "");
}
m_info.stackHeightInfo[&_literal] = m_stackHeight;
return true;
@@ -118,7 +118,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
m_errorReporter.declarationError(
_identifier.location,
- "Variable " + _identifier.name + " used before it was declared."
+ "Variable " + _identifier.name.str() + " used before it was declared."
);
success = false;
}
@@ -132,7 +132,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
m_errorReporter.typeError(
_identifier.location,
- "Function " + _identifier.name + " used without being called."
+ "Function " + _identifier.name.str() + " used without being called."
);
success = false;
}
@@ -253,7 +253,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
for (auto const& variable: _varDecl.variables)
{
- expectValidType(variable.type, variable.location);
+ expectValidType(variable.type.str(), variable.location);
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
}
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
@@ -268,7 +268,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
Scope& varScope = scope(virtualBlock);
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
{
- expectValidType(var.type, var.location);
+ expectValidType(var.type.str(), var.location);
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
}
@@ -361,7 +361,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
if (!expectExpression(*_switch.expression))
success = false;
- set<tuple<LiteralKind, string>> cases;
+ set<tuple<LiteralKind, YulString>> cases;
for (auto const& _case: _switch.cases)
{
if (_case.value)
@@ -503,7 +503,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
{
m_errorReporter.declarationError(
_variable.location,
- "Variable " + _variable.name + " used before it was declared."
+ "Variable " + _variable.name.str() + " used before it was declared."
);
success = false;
}
diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h
index 2982d5e0..a8d5e327 100644
--- a/libsolidity/inlineasm/AsmData.h
+++ b/libsolidity/inlineasm/AsmData.h
@@ -27,7 +27,13 @@
#include <libevmasm/Instruction.h>
#include <libevmasm/SourceLocation.h>
+#include <libyul/YulString.h>
+
#include <boost/variant.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <map>
+#include <memory>
namespace dev
{
@@ -36,20 +42,21 @@ namespace solidity
namespace assembly
{
-using Type = std::string;
+using YulString = dev::yul::YulString;
+using Type = YulString;
-struct TypedName { SourceLocation location; std::string name; Type type; };
+struct TypedName { SourceLocation location; YulString name; Type type; };
using TypedNameList = std::vector<TypedName>;
/// Direct EVM instruction (except PUSHi and JUMPDEST)
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
/// Literal number or string (up to 32 bytes)
enum class LiteralKind { Number, Boolean, String };
-struct Literal { SourceLocation location; LiteralKind kind; std::string value; Type type; };
+struct Literal { SourceLocation location; LiteralKind kind; YulString value; Type type; };
/// External / internal identifier or label reference
-struct Identifier { SourceLocation location; std::string name; };
+struct Identifier { SourceLocation location; YulString name; };
/// Jump label ("name:")
-struct Label { SourceLocation location; std::string name; };
+struct Label { SourceLocation location; YulString name; };
/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
struct StackAssignment { SourceLocation location; Identifier variableName; };
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
@@ -69,7 +76,7 @@ struct VariableDeclaration { SourceLocation location; TypedNameList variables; s
/// Block that creates a scope (frees declared stack variables)
struct Block { SourceLocation location; std::vector<Statement> statements; };
/// Function definition ("function f(a, b) -> (d, e) { ... }")
-struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
+struct FunctionDefinition { SourceLocation location; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
/// Conditional execution without "else" part.
struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
/// Switch case or default case
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index 54cdc1c6..1f399edc 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -112,8 +112,8 @@ assembly::Statement Parser::parseStatement()
advance();
expectToken(Token::Colon);
assignment.variableName.location = location();
- assignment.variableName.name = currentLiteral();
- if (instructions().count(assignment.variableName.name))
+ assignment.variableName.name = YulString(currentLiteral());
+ if (instructions().count(assignment.variableName.name.str()))
fatalParserError("Identifier expected, got instruction name.");
assignment.location.end = endPosition();
expectToken(Token::Identifier);
@@ -173,7 +173,7 @@ assembly::Statement Parser::parseStatement()
if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
{
assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location);
- if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name))
+ if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str()))
fatalParserError("Cannot use instruction names for identifier names.");
advance();
assignment.variableNames.emplace_back(identifier);
@@ -363,7 +363,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
ret = Instruction{location(), instr};
}
else
- ret = Identifier{location(), literal};
+ ret = Identifier{location(), YulString{literal}};
advance();
break;
}
@@ -394,15 +394,15 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
Literal literal{
location(),
kind,
- currentLiteral(),
- ""
+ YulString{currentLiteral()},
+ {}
};
advance();
if (m_flavour == AsmFlavour::Yul)
{
expectToken(Token::Colon);
literal.location.end = endPosition();
- literal.type = expectAsmIdentifier();
+ literal.type = YulString{expectAsmIdentifier()};
}
else if (kind == LiteralKind::Boolean)
fatalParserError("True and false are not valid literals.");
@@ -449,7 +449,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
RecursionGuard recursionGuard(*this);
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
expectToken(Token::Function);
- funDef.name = expectAsmIdentifier();
+ funDef.name = YulString{expectAsmIdentifier()};
expectToken(Token::LParen);
while (currentToken() != Token::RParen)
{
@@ -564,12 +564,12 @@ TypedName Parser::parseTypedName()
{
RecursionGuard recursionGuard(*this);
TypedName typedName = createWithLocation<TypedName>();
- typedName.name = expectAsmIdentifier();
+ typedName.name = YulString{expectAsmIdentifier()};
if (m_flavour == AsmFlavour::Yul)
{
expectToken(Token::Colon);
typedName.location.end = endPosition();
- typedName.type = expectAsmIdentifier();
+ typedName.type = YulString{expectAsmIdentifier()};
}
return typedName;
}
diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
index 4b8c9538..ae0bd1eb 100644
--- a/libsolidity/inlineasm/AsmPrinter.cpp
+++ b/libsolidity/inlineasm/AsmPrinter.cpp
@@ -52,17 +52,17 @@ string AsmPrinter::operator()(assembly::Literal const& _literal)
switch (_literal.kind)
{
case LiteralKind::Number:
- solAssert(isValidDecimal(_literal.value) || isValidHex(_literal.value), "Invalid number literal");
- return _literal.value + appendTypeName(_literal.type);
+ solAssert(isValidDecimal(_literal.value.str()) || isValidHex(_literal.value.str()), "Invalid number literal");
+ return _literal.value.str() + appendTypeName(_literal.type);
case LiteralKind::Boolean:
- solAssert(_literal.value == "true" || _literal.value == "false", "Invalid bool literal.");
- return ((_literal.value == "true") ? "true" : "false") + appendTypeName(_literal.type);
+ solAssert(_literal.value.str() == "true" || _literal.value.str() == "false", "Invalid bool literal.");
+ return ((_literal.value.str() == "true") ? "true" : "false") + appendTypeName(_literal.type);
case LiteralKind::String:
break;
}
string out;
- for (char c: _literal.value)
+ for (char c: _literal.value.str())
if (c == '\\')
out += "\\\\";
else if (c == '"')
@@ -93,7 +93,7 @@ string AsmPrinter::operator()(assembly::Literal const& _literal)
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
{
solAssert(!_identifier.name.empty(), "Invalid identifier.");
- return _identifier.name;
+ return _identifier.name.str();
}
string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction)
@@ -118,7 +118,7 @@ string AsmPrinter::operator()(assembly::Label const& _label)
{
solAssert(!m_yul, "");
solAssert(!_label.name.empty(), "Invalid label.");
- return _label.name + ":";
+ return _label.name.str() + ":";
}
string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
@@ -157,7 +157,7 @@ string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDecl
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
{
solAssert(!_functionDefinition.name.empty(), "Invalid function name.");
- string out = "function " + _functionDefinition.name + "(";
+ string out = "function " + _functionDefinition.name.str() + "(";
out += boost::algorithm::join(
_functionDefinition.parameters | boost::adaptors::transformed(
[this](TypedName argument) { return formatTypedName(argument); }
@@ -239,12 +239,12 @@ string AsmPrinter::operator()(Block const& _block)
string AsmPrinter::formatTypedName(TypedName _variable) const
{
solAssert(!_variable.name.empty(), "Invalid variable name.");
- return _variable.name + appendTypeName(_variable.type);
+ return _variable.name.str() + appendTypeName(_variable.type);
}
-string AsmPrinter::appendTypeName(std::string const& _type) const
+string AsmPrinter::appendTypeName(YulString _type) const
{
if (m_yul)
- return ":" + _type;
+ return ":" + _type.str();
return "";
}
diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h
index 971822bf..72048975 100644
--- a/libsolidity/inlineasm/AsmPrinter.h
+++ b/libsolidity/inlineasm/AsmPrinter.h
@@ -24,6 +24,8 @@
#include <libsolidity/inlineasm/AsmDataForward.h>
+#include <libyul/YulString.h>
+
#include <boost/variant.hpp>
namespace dev
@@ -56,7 +58,7 @@ public:
private:
std::string formatTypedName(TypedName _variable) const;
- std::string appendTypeName(std::string const& _type) const;
+ std::string appendTypeName(yul::YulString _type) const;
bool m_yul = false;
};
diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp
index af81b301..019170ca 100644
--- a/libsolidity/inlineasm/AsmScope.cpp
+++ b/libsolidity/inlineasm/AsmScope.cpp
@@ -24,7 +24,7 @@ using namespace std;
using namespace dev::solidity::assembly;
-bool Scope::registerLabel(string const& _name)
+bool Scope::registerLabel(yul::YulString _name)
{
if (exists(_name))
return false;
@@ -32,7 +32,7 @@ bool Scope::registerLabel(string const& _name)
return true;
}
-bool Scope::registerVariable(string const& _name, YulType const& _type)
+bool Scope::registerVariable(yul::YulString _name, YulType const& _type)
{
if (exists(_name))
return false;
@@ -42,7 +42,7 @@ bool Scope::registerVariable(string const& _name, YulType const& _type)
return true;
}
-bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
+bool Scope::registerFunction(yul::YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
{
if (exists(_name))
return false;
@@ -50,7 +50,7 @@ bool Scope::registerFunction(string const& _name, std::vector<YulType> const& _a
return true;
}
-Scope::Identifier* Scope::lookup(string const& _name)
+Scope::Identifier* Scope::lookup(yul::YulString _name)
{
bool crossedFunctionBoundary = false;
for (Scope* s = this; s; s = s->superScope)
@@ -70,7 +70,7 @@ Scope::Identifier* Scope::lookup(string const& _name)
return nullptr;
}
-bool Scope::exists(string const& _name) const
+bool Scope::exists(yul::YulString _name) const
{
if (identifiers.count(_name))
return true;
diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h
index fc674e71..65848018 100644
--- a/libsolidity/inlineasm/AsmScope.h
+++ b/libsolidity/inlineasm/AsmScope.h
@@ -22,6 +22,8 @@
#include <libsolidity/interface/Exceptions.h>
+#include <libyul/YulString.h>
+
#include <libdevcore/Visitor.h>
#include <boost/variant.hpp>
@@ -39,7 +41,7 @@ namespace assembly
struct Scope
{
- using YulType = std::string;
+ using YulType = yul::YulString;
using LabelID = size_t;
struct Variable { YulType type; };
@@ -54,10 +56,10 @@ struct Scope
using Visitor = GenericVisitor<Variable const, Label const, Function const>;
using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
- bool registerVariable(std::string const& _name, YulType const& _type);
- bool registerLabel(std::string const& _name);
+ bool registerVariable(yul::YulString _name, YulType const& _type);
+ bool registerLabel(yul::YulString _name);
bool registerFunction(
- std::string const& _name,
+ yul::YulString _name,
std::vector<YulType> const& _arguments,
std::vector<YulType> const& _returns
);
@@ -67,12 +69,12 @@ struct Scope
/// will any lookups across assembly boundaries.
/// The pointer will be invalidated if the scope is modified.
/// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup
- Identifier* lookup(std::string const& _name);
+ Identifier* lookup(yul::YulString _name);
/// Looks up the identifier in this and super scopes (will not find variables across function
/// boundaries and generally stops at assembly boundaries) and calls the visitor, returns
/// false if not found.
template <class V>
- bool lookup(std::string const& _name, V const& _visitor)
+ bool lookup(yul::YulString _name, V const& _visitor)
{
if (Identifier* id = lookup(_name))
{
@@ -84,7 +86,7 @@ struct Scope
}
/// @returns true if the name exists in this scope or in super scopes (also searches
/// across function and assembly boundaries).
- bool exists(std::string const& _name) const;
+ bool exists(yul::YulString _name) const;
/// @returns the number of variables directly registered inside the scope.
size_t numberOfVariables() const;
@@ -95,7 +97,7 @@ struct Scope
/// If true, variables from the super scope are not visible here (other identifiers are),
/// but they are still taken into account to prevent shadowing.
bool functionScope = false;
- std::map<std::string, Identifier> identifiers;
+ std::map<yul::YulString, Identifier> identifiers;
};
}
diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp
index 2d15c820..d1f98083 100644
--- a/libsolidity/inlineasm/AsmScopeFiller.cpp
+++ b/libsolidity/inlineasm/AsmScopeFiller.cpp
@@ -57,7 +57,7 @@ bool ScopeFiller::operator()(Label const& _item)
//@TODO secondary location
m_errorReporter.declarationError(
_item.location,
- "Label name " + _item.name + " already taken in this scope."
+ "Label name " + _item.name.str() + " already taken in this scope."
);
return false;
}
@@ -77,16 +77,16 @@ bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
bool success = true;
vector<Scope::YulType> arguments;
for (auto const& _argument: _funDef.parameters)
- arguments.push_back(_argument.type);
+ arguments.emplace_back(_argument.type.str());
vector<Scope::YulType> returns;
for (auto const& _return: _funDef.returnVariables)
- returns.push_back(_return.type);
+ returns.emplace_back(_return.type.str());
if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
{
//@TODO secondary location
m_errorReporter.declarationError(
_funDef.location,
- "Function name " + _funDef.name + " already taken in this scope."
+ "Function name " + _funDef.name.str() + " already taken in this scope."
);
success = false;
}
@@ -164,7 +164,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const&
//@TODO secondary location
m_errorReporter.declarationError(
_location,
- "Variable name " + _name.name + " already taken in this scope."
+ "Variable name " + _name.name.str() + " already taken in this scope."
);
return false;
}
diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp
index a35bfd29..b5f68ce8 100644
--- a/libsolidity/interface/Version.cpp
+++ b/libsolidity/interface/Version.cpp
@@ -55,13 +55,13 @@ bytes dev::solidity::binaryVersion()
ret = ret * 10 + (VersionString[i] - '0');
return ret;
};
- ret.push_back(byte(parseDecimal()));
+ ret.push_back(uint8_t(parseDecimal()));
solAssert(i < VersionString.size() && VersionString[i] == '.', "");
++i;
- ret.push_back(byte(parseDecimal()));
+ ret.push_back(uint8_t(parseDecimal()));
solAssert(i < VersionString.size() && VersionString[i] == '.', "");
++i;
- ret.push_back(byte(parseDecimal()));
+ ret.push_back(uint8_t(parseDecimal()));
solAssert(i < VersionString.size() && (VersionString[i] == '-' || VersionString[i] == '+'), "");
++i;
size_t commitpos = VersionString.find("commit.");
diff --git a/libyul/ASTDataForward.h b/libyul/ASTDataForward.h
index 7f131b5e..8c49e68f 100644
--- a/libyul/ASTDataForward.h
+++ b/libyul/ASTDataForward.h
@@ -46,6 +46,7 @@ using ExpressionStatement = solidity::assembly::ExpressionStatement;
using Block = solidity::assembly::Block;
using TypedName = solidity::assembly::TypedName;
+class YulString;
using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h
index c423b66f..0c421dbf 100644
--- a/libyul/Exceptions.h
+++ b/libyul/Exceptions.h
@@ -30,6 +30,11 @@ namespace yul
struct YulException: virtual Exception {};
struct OptimizerException: virtual YulException {};
+struct YulAssertion: virtual YulException {};
+
+/// Assertion that throws an YulAssertion containing the given description if it is not met.
+#define yulAssert(CONDITION, DESCRIPTION) \
+ assertThrow(CONDITION, ::dev::yul::YulException, DESCRIPTION)
}
}
diff --git a/libyul/YulString.h b/libyul/YulString.h
new file mode 100644
index 00000000..ae01c83f
--- /dev/null
+++ b/libyul/YulString.h
@@ -0,0 +1,96 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * String abstraction that avoids copies.
+ */
+
+#pragma once
+
+#include <boost/noncopyable.hpp>
+
+#include <map>
+#include <memory>
+#include <vector>
+#include <string>
+
+namespace dev
+{
+namespace yul
+{
+
+class YulStringRepository: boost::noncopyable
+{
+public:
+ YulStringRepository(): m_strings{std::make_shared<std::string>()}
+ {
+ m_ids[std::string{}] = 0;
+ }
+ static YulStringRepository& instance()
+ {
+ static YulStringRepository inst;
+ return inst;
+ }
+ size_t stringToId(std::string const& _string)
+ {
+ if (_string.empty())
+ return 0;
+ size_t& id = m_ids[_string];
+ if (id == 0)
+ {
+ m_strings.emplace_back(std::make_shared<std::string>(_string));
+ id = m_strings.size() - 1;
+ }
+ return id;
+ }
+ std::string const& idToString(size_t _id) const
+ {
+ return *m_strings.at(_id);
+ }
+
+private:
+ std::vector<std::shared_ptr<std::string>> m_strings;
+ std::map<std::string, size_t> m_ids;
+};
+
+class YulString
+{
+public:
+ YulString() = default;
+ explicit YulString(std::string const& _s): m_id(YulStringRepository::instance().stringToId(_s)) {}
+ YulString(YulString const&) = default;
+ YulString(YulString&&) = default;
+ YulString& operator=(YulString const&) = default;
+ YulString& operator=(YulString&&) = default;
+
+ /// This is not consistent with the string <-operator!
+ bool operator<(YulString const& _other) const { return m_id < _other.m_id; }
+ bool operator==(YulString const& _other) const { return m_id == _other.m_id; }
+ bool operator!=(YulString const& _other) const { return m_id != _other.m_id; }
+
+ bool empty() const { return m_id == 0; }
+ std::string const& str() const
+ {
+ return YulStringRepository::instance().idToString(m_id);
+ }
+
+private:
+ /// ID of the string. Assumes that the empty string has ID zero.
+ size_t m_id = 0;
+};
+
+}
+}
diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp
index b2f0878f..b37a3231 100644
--- a/libyul/backends/evm/EVMAssembly.cpp
+++ b/libyul/backends/evm/EVMAssembly.cpp
@@ -44,7 +44,7 @@ void EVMAssembly::setSourceLocation(SourceLocation const&)
void EVMAssembly::appendInstruction(solidity::Instruction _instr)
{
- m_bytecode.push_back(byte(_instr));
+ m_bytecode.push_back(uint8_t(_instr));
m_stackHeight += solidity::instructionInfo(_instr).ret - solidity::instructionInfo(_instr).args;
}
@@ -101,7 +101,7 @@ void EVMAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
{
if (m_evm15)
{
- m_bytecode.push_back(byte(solidity::Instruction::JUMPTO));
+ m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPTO));
appendLabelReferenceInternal(_labelId);
m_stackHeight += _stackDiffAfter;
}
@@ -116,7 +116,7 @@ void EVMAssembly::appendJumpToIf(LabelID _labelId)
{
if (m_evm15)
{
- m_bytecode.push_back(byte(solidity::Instruction::JUMPIF));
+ m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPIF));
appendLabelReferenceInternal(_labelId);
m_stackHeight--;
}
@@ -132,7 +132,7 @@ void EVMAssembly::appendBeginsub(LabelID _labelId, int _arguments)
solAssert(m_evm15, "BEGINSUB used for EVM 1.0");
solAssert(_arguments >= 0, "");
setLabelToCurrentPosition(_labelId);
- m_bytecode.push_back(byte(solidity::Instruction::BEGINSUB));
+ m_bytecode.push_back(uint8_t(solidity::Instruction::BEGINSUB));
m_stackHeight += _arguments;
}
@@ -140,7 +140,7 @@ void EVMAssembly::appendJumpsub(LabelID _labelId, int _arguments, int _returns)
{
solAssert(m_evm15, "JUMPSUB used for EVM 1.0");
solAssert(_arguments >= 0 && _returns >= 0, "");
- m_bytecode.push_back(byte(solidity::Instruction::JUMPSUB));
+ m_bytecode.push_back(uint8_t(solidity::Instruction::JUMPSUB));
appendLabelReferenceInternal(_labelId);
m_stackHeight += _returns - _arguments;
}
@@ -149,7 +149,7 @@ void EVMAssembly::appendReturnsub(int _returns, int _stackDiffAfter)
{
solAssert(m_evm15, "RETURNSUB used for EVM 1.0");
solAssert(_returns >= 0, "");
- m_bytecode.push_back(byte(solidity::Instruction::RETURNSUB));
+ m_bytecode.push_back(uint8_t(solidity::Instruction::RETURNSUB));
m_stackHeight += _stackDiffAfter - _returns;
}
@@ -198,5 +198,5 @@ void EVMAssembly::updateReference(size_t pos, size_t size, u256 value)
solAssert(m_bytecode.size() >= size && pos <= m_bytecode.size() - size, "");
solAssert(value < (u256(1) << (8 * size)), "");
for (size_t i = 0; i < size; i++)
- m_bytecode[pos + i] = byte((value >> (8 * (size - i - 1))) & 0xff);
+ m_bytecode[pos + i] = uint8_t((value >> (8 * (size - i - 1))) & 0xff);
}
diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp
index 89086b4e..650a8c0a 100644
--- a/libyul/backends/evm/EVMCodeTransform.cpp
+++ b/libyul/backends/evm/EVMCodeTransform.cpp
@@ -201,18 +201,18 @@ void CodeTransform::operator()(assembly::Literal const& _literal)
{
m_assembly.setSourceLocation(_literal.location);
if (_literal.kind == assembly::LiteralKind::Number)
- m_assembly.appendConstant(u256(_literal.value));
+ m_assembly.appendConstant(u256(_literal.value.str()));
else if (_literal.kind == assembly::LiteralKind::Boolean)
{
- if (_literal.value == "true")
+ if (_literal.value.str() == "true")
m_assembly.appendConstant(u256(1));
else
m_assembly.appendConstant(u256(0));
}
else
{
- solAssert(_literal.value.size() <= 32, "");
- m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft)));
+ solAssert(_literal.value.str().size() <= 32, "");
+ m_assembly.appendConstant(u256(h256(_literal.value.str(), h256::FromBinary, h256::AlignLeft)));
}
checkStackHeight(&_literal);
}
@@ -454,13 +454,13 @@ AbstractAssembly::LabelID CodeTransform::labelID(Scope::Label const& _label)
return m_context->labelIDs[&_label];
}
-AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Scope::Function const& _function)
+AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function)
{
if (!m_context->functionEntryIDs.count(&_function))
{
AbstractAssembly::LabelID id =
m_useNamedLabelsForFunctions ?
- m_assembly.namedLabel(_name) :
+ m_assembly.namedLabel(_name.str()) :
m_assembly.newLabelId();
m_context->functionEntryIDs[&_function] = id;
}
diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h
index 22ebbf43..c0de8ad6 100644
--- a/libyul/backends/evm/EVMCodeTransform.h
+++ b/libyul/backends/evm/EVMCodeTransform.h
@@ -117,7 +117,7 @@ private:
/// @returns the label ID corresponding to the given label, allocating a new one if
/// necessary.
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
- AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function);
+ AbstractAssembly::LabelID functionEntryID(YulString _name, solidity::assembly::Scope::Function const& _function);
/// Generates code for an expression that is supposed to return a single value.
void visitExpression(Expression const& _expression);
diff --git a/libyul/optimiser/ASTCopier.cpp b/libyul/optimiser/ASTCopier.cpp
index 4b7f21f8..d0c8dd45 100644
--- a/libyul/optimiser/ASTCopier.cpp
+++ b/libyul/optimiser/ASTCopier.cpp
@@ -111,14 +111,14 @@ Statement ASTCopier::operator()(Switch const& _switch)
Statement ASTCopier::operator()(FunctionDefinition const& _function)
{
- string translatedName = translateIdentifier(_function.name);
+ YulString translatedName = translateIdentifier(_function.name);
enterFunction(_function);
ScopeGuard g([&]() { this->leaveFunction(_function); });
return FunctionDefinition{
_function.location,
- move(translatedName),
+ translatedName,
translateVector(_function.parameters),
translateVector(_function.returnVariables),
translate(_function.body)
diff --git a/libyul/optimiser/ASTCopier.h b/libyul/optimiser/ASTCopier.h
index 13369cef..b6aceee3 100644
--- a/libyul/optimiser/ASTCopier.h
+++ b/libyul/optimiser/ASTCopier.h
@@ -22,6 +22,8 @@
#include <libyul/ASTDataForward.h>
+#include <libyul/YulString.h>
+
#include <boost/variant.hpp>
#include <boost/optional.hpp>
@@ -107,7 +109,7 @@ protected:
virtual void leaveScope(Block const&) { }
virtual void enterFunction(FunctionDefinition const&) { }
virtual void leaveFunction(FunctionDefinition const&) { }
- virtual std::string translateIdentifier(std::string const& _name) { return _name; }
+ virtual YulString translateIdentifier(YulString _name) { return _name; }
};
template <typename T>
diff --git a/libyul/optimiser/ASTWalker.h b/libyul/optimiser/ASTWalker.h
index 41617d55..38cb85ea 100644
--- a/libyul/optimiser/ASTWalker.h
+++ b/libyul/optimiser/ASTWalker.h
@@ -23,6 +23,7 @@
#include <libyul/ASTDataForward.h>
#include <libyul/Exceptions.h>
+#include <libyul/YulString.h>
#include <boost/variant.hpp>
#include <boost/optional.hpp>
diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp
index 51737097..64605362 100644
--- a/libyul/optimiser/CommonSubexpressionEliminator.cpp
+++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp
@@ -43,13 +43,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
if (_e.type() == typeid(Identifier))
{
Identifier& identifier = boost::get<Identifier>(_e);
- string const& name = identifier.name;
+ YulString name = identifier.name;
if (m_value.count(name))
{
assertThrow(m_value.at(name), OptimizerException, "");
if (m_value.at(name)->type() == typeid(Identifier))
{
- string const& value = boost::get<Identifier>(*m_value.at(name)).name;
+ YulString value = boost::get<Identifier>(*m_value.at(name)).name;
assertThrow(inScope(value), OptimizerException, "");
_e = Identifier{locationOf(_e), value};
}
diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp
index 7ac42c30..1ff1d2f0 100644
--- a/libyul/optimiser/DataFlowAnalyzer.cpp
+++ b/libyul/optimiser/DataFlowAnalyzer.cpp
@@ -38,9 +38,9 @@ using namespace dev::yul;
void DataFlowAnalyzer::operator()(Assignment& _assignment)
{
- set<string> names;
+ set<YulString> names;
for (auto const& var: _assignment.variableNames)
- names.insert(var.name);
+ names.emplace(var.name);
assertThrow(_assignment.value, OptimizerException, "");
visit(*_assignment.value);
handleAssignment(names, _assignment.value.get());
@@ -48,9 +48,9 @@ void DataFlowAnalyzer::operator()(Assignment& _assignment)
void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
{
- set<string> names;
+ set<YulString> names;
for (auto const& var: _varDecl.variables)
- names.insert(var.name);
+ names.emplace(var.name);
m_variableScopes.back().variables += names;
if (_varDecl.value)
visit(*_varDecl.value);
@@ -69,7 +69,7 @@ void DataFlowAnalyzer::operator()(If& _if)
void DataFlowAnalyzer::operator()(Switch& _switch)
{
visit(*_switch.expression);
- set<string> assignedVariables;
+ set<YulString> assignedVariables;
for (auto& _case: _switch.cases)
{
(*this)(_case.body);
@@ -86,9 +86,9 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun)
{
pushScope(true);
for (auto const& parameter: _fun.parameters)
- m_variableScopes.back().variables.insert(parameter.name);
+ m_variableScopes.back().variables.emplace(parameter.name);
for (auto const& var: _fun.returnVariables)
- m_variableScopes.back().variables.insert(var.name);
+ m_variableScopes.back().variables.emplace(var.name);
ASTModifier::operator()(_fun);
popScope();
}
@@ -122,7 +122,7 @@ void DataFlowAnalyzer::operator()(Block& _block)
assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
}
-void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expression* _value)
+void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value)
{
clearValues(_variables);
@@ -131,7 +131,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio
movableChecker.visit(*_value);
if (_variables.size() == 1)
{
- string const& name = *_variables.begin();
+ YulString name = *_variables.begin();
// Expression has to be movable and cannot contain a reference
// to the variable that will be assigned to.
if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name))
@@ -143,7 +143,7 @@ void DataFlowAnalyzer::handleAssignment(set<string> const& _variables, Expressio
{
m_references[name] = referencedVariables;
for (auto const& ref: referencedVariables)
- m_referencedBy[ref].insert(name);
+ m_referencedBy[ref].emplace(name);
}
}
@@ -158,7 +158,7 @@ void DataFlowAnalyzer::popScope()
m_variableScopes.pop_back();
}
-void DataFlowAnalyzer::clearValues(set<string> _variables)
+void DataFlowAnalyzer::clearValues(set<YulString> _variables)
{
// All variables that reference variables to be cleared also have to be
// cleared, but not recursively, since only the value of the original
@@ -176,7 +176,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables)
// Clear variables that reference variables to be cleared.
for (auto const& name: _variables)
for (auto const& ref: m_referencedBy[name])
- _variables.insert(ref);
+ _variables.emplace(ref);
// Clear the value and update the reference relation.
for (auto const& name: _variables)
@@ -189,7 +189,7 @@ void DataFlowAnalyzer::clearValues(set<string> _variables)
}
}
-bool DataFlowAnalyzer::inScope(string const& _variableName) const
+bool DataFlowAnalyzer::inScope(YulString _variableName) const
{
for (auto const& scope: m_variableScopes | boost::adaptors::reversed)
{
diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h
index 95671467..a0c21eee 100644
--- a/libyul/optimiser/DataFlowAnalyzer.h
+++ b/libyul/optimiser/DataFlowAnalyzer.h
@@ -24,7 +24,8 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <string>
+#include <libyul/YulString.h>
+
#include <map>
#include <set>
@@ -54,7 +55,7 @@ public:
protected:
/// Registers the assignment.
- void handleAssignment(std::set<std::string> const& _names, Expression* _value);
+ void handleAssignment(std::set<YulString> const& _names, Expression* _value);
/// Creates a new inner scope.
void pushScope(bool _functionScope);
@@ -64,22 +65,22 @@ protected:
/// Clears information about the values assigned to the given variables,
/// for example at points where control flow is merged.
- void clearValues(std::set<std::string> _names);
+ void clearValues(std::set<YulString> _names);
/// Returns true iff the variable is in scope.
- bool inScope(std::string const& _variableName) const;
+ bool inScope(YulString _variableName) const;
/// Current values of variables, always movable.
- std::map<std::string, Expression const*> m_value;
+ std::map<YulString, Expression const*> m_value;
/// m_references[a].contains(b) <=> the current expression assigned to a references b
- std::map<std::string, std::set<std::string>> m_references;
+ std::map<YulString, std::set<YulString>> m_references;
/// m_referencedBy[b].contains(a) <=> the current expression assigned to a references b
- std::map<std::string, std::set<std::string>> m_referencedBy;
+ std::map<YulString, std::set<YulString>> m_referencedBy;
struct Scope
{
explicit Scope(bool _isFunction): isFunction(_isFunction) {}
- std::set<std::string> variables;
+ std::set<YulString> variables;
bool isFunction;
};
/// List of scopes.
diff --git a/libyul/optimiser/Disambiguator.cpp b/libyul/optimiser/Disambiguator.cpp
index dcba97c9..4303f412 100644
--- a/libyul/optimiser/Disambiguator.cpp
+++ b/libyul/optimiser/Disambiguator.cpp
@@ -32,7 +32,7 @@ using namespace dev::solidity;
using Scope = dev::solidity::assembly::Scope;
-string Disambiguator::translateIdentifier(string const& _originalName)
+YulString Disambiguator::translateIdentifier(YulString _originalName)
{
if ((m_externallyUsedIdentifiers.count(_originalName)))
return _originalName;
diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h
index 74a491ab..bfb65682 100644
--- a/libyul/optimiser/Disambiguator.h
+++ b/libyul/optimiser/Disambiguator.h
@@ -45,7 +45,7 @@ class Disambiguator: public ASTCopier
public:
explicit Disambiguator(
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
- std::set<std::string> const& _externallyUsedIdentifiers = {}
+ std::set<YulString> const& _externallyUsedIdentifiers = {}
):
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers)
{
@@ -56,16 +56,16 @@ protected:
virtual void leaveScope(Block const& _block) override;
virtual void enterFunction(FunctionDefinition const& _function) override;
virtual void leaveFunction(FunctionDefinition const& _function) override;
- virtual std::string translateIdentifier(std::string const& _name) override;
+ virtual YulString translateIdentifier(YulString _name) override;
void enterScopeInternal(solidity::assembly::Scope& _scope);
void leaveScopeInternal(solidity::assembly::Scope& _scope);
solidity::assembly::AsmAnalysisInfo const& m_info;
- std::set<std::string> const& m_externallyUsedIdentifiers;
+ std::set<YulString> const& m_externallyUsedIdentifiers;
std::vector<solidity::assembly::Scope*> m_scopes;
- std::map<void const*, std::string> m_translations;
+ std::map<void const*, YulString> m_translations;
NameDispenser m_nameDispenser;
};
diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp
index 9bf0a3fb..07e88191 100644
--- a/libyul/optimiser/ExpressionInliner.cpp
+++ b/libyul/optimiser/ExpressionInliner.cpp
@@ -62,7 +62,7 @@ void ExpressionInliner::visit(Expression& _expression)
if (m_inlinableFunctions.count(funCall.functionName.name) && movable)
{
FunctionDefinition const& fun = *m_inlinableFunctions.at(funCall.functionName.name);
- map<string, Expression const*> substitutions;
+ map<YulString, Expression const*> substitutions;
for (size_t i = 0; i < fun.parameters.size(); ++i)
substitutions[fun.parameters[i].name] = &funCall.arguments[i];
_expression = Substitution(substitutions).translate(*boost::get<Assignment>(fun.body.statements.front()).value);
diff --git a/libyul/optimiser/ExpressionInliner.h b/libyul/optimiser/ExpressionInliner.h
index 971a2ee0..d903664f 100644
--- a/libyul/optimiser/ExpressionInliner.h
+++ b/libyul/optimiser/ExpressionInliner.h
@@ -59,10 +59,10 @@ public:
virtual void visit(Expression& _expression) override;
private:
- std::map<std::string, FunctionDefinition const*> m_inlinableFunctions;
- std::map<std::string, std::string> m_varReplacements;
+ std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
+ std::map<YulString, YulString> m_varReplacements;
/// Set of functions we are currently visiting inside.
- std::set<std::string> m_currentFunctions;
+ std::set<YulString> m_currentFunctions;
Block& m_block;
};
diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp
index c3957497..7e57a629 100644
--- a/libyul/optimiser/ExpressionJoiner.cpp
+++ b/libyul/optimiser/ExpressionJoiner.cpp
@@ -46,20 +46,6 @@ void ExpressionJoiner::operator()(FunctionCall& _funCall)
handleArguments(_funCall.arguments);
}
-void ExpressionJoiner::operator()(If& _if)
-{
- visit(*_if.condition);
- (*this)(_if.body);
-}
-
-void ExpressionJoiner::operator()(Switch& _switch)
-{
- visit(*_switch.expression);
- for (auto& _case: _switch.cases)
- // Do not visit the case expression, nothing to join there.
- (*this)(_case.body);
-}
-
void ExpressionJoiner::operator()(Block& _block)
{
resetLatestStatementPointer();
@@ -79,13 +65,11 @@ void ExpressionJoiner::visit(Expression& _e)
if (_e.type() == typeid(Identifier))
{
Identifier const& identifier = boost::get<Identifier>(_e);
- if (isLatestStatementVarDeclOf(identifier) && m_references[identifier.name] == 1)
+ if (isLatestStatementVarDeclJoinable(identifier))
{
VariableDeclaration& varDecl = boost::get<VariableDeclaration>(*latestStatement());
- assertThrow(varDecl.variables.size() == 1, OptimizerException, "");
- assertThrow(varDecl.value, OptimizerException, "");
-
_e = std::move(*varDecl.value);
+
// Delete the variable declaration (also get the moved-from structure back into a sane state)
*latestStatement() = Block();
@@ -103,9 +87,7 @@ void ExpressionJoiner::run(Block& _ast)
ExpressionJoiner::ExpressionJoiner(Block& _ast)
{
- ReferencesCounter counter;
- counter(_ast);
- m_references = counter.references();
+ m_references = ReferencesCounter::countReferences(_ast);
}
void ExpressionJoiner::handleArguments(vector<Expression>& _arguments)
@@ -154,7 +136,7 @@ Statement* ExpressionJoiner::latestStatement()
return &m_currentBlock->statements.at(m_latestStatementInBlock);
}
-bool ExpressionJoiner::isLatestStatementVarDeclOf(Identifier const& _identifier)
+bool ExpressionJoiner::isLatestStatementVarDeclJoinable(Identifier const& _identifier)
{
Statement const* statement = latestStatement();
if (!statement || statement->type() != typeid(VariableDeclaration))
@@ -162,5 +144,7 @@ bool ExpressionJoiner::isLatestStatementVarDeclOf(Identifier const& _identifier)
VariableDeclaration const& varDecl = boost::get<VariableDeclaration>(*statement);
if (varDecl.variables.size() != 1 || !varDecl.value)
return false;
- return varDecl.variables.at(0).name == _identifier.name;
+ assertThrow(varDecl.variables.size() == 1, OptimizerException, "");
+ assertThrow(varDecl.value, OptimizerException, "");
+ return varDecl.variables.at(0).name == _identifier.name && m_references[_identifier.name] == 1;
}
diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h
index df18e58f..0cc61981 100644
--- a/libyul/optimiser/ExpressionJoiner.h
+++ b/libyul/optimiser/ExpressionJoiner.h
@@ -73,29 +73,29 @@ class NameCollector;
class ExpressionJoiner: public ASTModifier
{
public:
- virtual void operator()(FunctionalInstruction&) override;
- virtual void operator()(FunctionCall&) override;
- virtual void operator()(If&) override;
- virtual void operator()(Switch&) override;
- virtual void operator()(Block& _block) override;
-
- using ASTModifier::visit;
- virtual void visit(Expression& _e) override;
-
static void run(Block& _ast);
+
private:
explicit ExpressionJoiner(Block& _ast);
+ void operator()(Block& _block) override;
+ void operator()(FunctionalInstruction&) override;
+ void operator()(FunctionCall&) override;
+
+ using ASTModifier::visit;
+ void visit(Expression& _e) override;
+
void handleArguments(std::vector<Expression>& _arguments);
void decrementLatestStatementPointer();
void resetLatestStatementPointer();
Statement* latestStatement();
- bool isLatestStatementVarDeclOf(Identifier const& _identifier);
+ bool isLatestStatementVarDeclJoinable(Identifier const& _identifier);
- Block* m_currentBlock = nullptr;
- size_t m_latestStatementInBlock = 0;
- std::map<std::string, size_t> m_references;
+private:
+ Block* m_currentBlock = nullptr; ///< Pointer to current block holding the statement being visited.
+ size_t m_latestStatementInBlock = 0; ///< Offset to m_currentBlock's statements of the last visited statement.
+ std::map<YulString, size_t> m_references; ///< Holds reference counts to all variable declarations in current block.
};
}
diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h
index 5419ff6a..5965a1bb 100644
--- a/libyul/optimiser/ExpressionSimplifier.h
+++ b/libyul/optimiser/ExpressionSimplifier.h
@@ -44,11 +44,11 @@ public:
static void run(Block& _ast);
private:
- explicit ExpressionSimplifier(std::map<std::string, Expression const*> _ssaValues):
+ explicit ExpressionSimplifier(std::map<YulString, Expression const*> _ssaValues):
m_ssaValues(std::move(_ssaValues))
{}
- std::map<std::string, Expression const*> m_ssaValues;
+ std::map<YulString, Expression const*> m_ssaValues;
};
}
diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp
index a2ecc546..a4b7a909 100644
--- a/libyul/optimiser/ExpressionSplitter.cpp
+++ b/libyul/optimiser/ExpressionSplitter.cpp
@@ -95,10 +95,10 @@ void ExpressionSplitter::outlineExpression(Expression& _expr)
visit(_expr);
SourceLocation location = locationOf(_expr);
- string var = m_nameDispenser.newName("");
+ YulString var = m_nameDispenser.newName({});
m_statementsToPrefix.emplace_back(VariableDeclaration{
location,
- {{TypedName{location, var, ""}}},
+ {{TypedName{location, var, {}}}},
make_shared<Expression>(std::move(_expr))
});
_expr = Identifier{location, var};
diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp
index 280d625a..c9057cf3 100644
--- a/libyul/optimiser/FullInliner.cpp
+++ b/libyul/optimiser/FullInliner.cpp
@@ -48,9 +48,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
tracker(m_ast);
for (auto const& ssaValue: tracker.values())
if (ssaValue.second && ssaValue.second->type() == typeid(Literal))
- m_constants.insert(ssaValue.first);
+ m_constants.emplace(ssaValue.first);
- map<string, size_t> references = ReferencesCounter::countReferences(m_ast);
+ map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast);
for (auto& statement: m_ast.statements)
{
if (statement.type() != typeid(FunctionDefinition))
@@ -59,7 +59,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
m_functions[fun.name] = &fun;
// Always inline functions that are only called once.
if (references[fun.name] == 1)
- m_alwaysInline.insert(fun.name);
+ m_alwaysInline.emplace(fun.name);
updateCodeSize(fun);
}
}
@@ -68,7 +68,7 @@ void FullInliner::run()
{
for (auto& statement: m_ast.statements)
if (statement.type() == typeid(Block))
- handleBlock("", boost::get<Block>(statement));
+ handleBlock({}, boost::get<Block>(statement));
// TODO it might be good to determine a visiting order:
// first handle functions that are called from many places.
@@ -84,12 +84,12 @@ void FullInliner::updateCodeSize(FunctionDefinition& fun)
m_functionSizes[fun.name] = CodeSize::codeSize(fun.body);
}
-void FullInliner::handleBlock(string const& _currentFunctionName, Block& _block)
+void FullInliner::handleBlock(YulString _currentFunctionName, Block& _block)
{
InlineModifier{*this, m_nameDispenser, _currentFunctionName}(_block);
}
-bool FullInliner::shallInline(FunctionCall const& _funCall, string const& _callSite)
+bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
{
// No recursive inlining
if (_funCall.functionName.name == _callSite)
@@ -148,14 +148,14 @@ boost::optional<vector<Statement>> InlineModifier::tryInlineStatement(Statement&
vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionCall& _funCall)
{
vector<Statement> newStatements;
- map<string, string> variableReplacements;
+ map<YulString, YulString> variableReplacements;
FunctionDefinition& function = m_driver.function(_funCall.functionName.name);
// helper function to create a new variable that is supposed to model
// an existing variable.
auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) {
- string newName = m_nameDispenser.newName(_existingVariable.name, function.name);
+ YulString newName = m_nameDispenser.newName(_existingVariable.name, function.name);
variableReplacements[_existingVariable.name] = newName;
VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}};
if (_value)
@@ -214,7 +214,7 @@ Statement BodyCopier::operator()(FunctionDefinition const& _funDef)
return _funDef;
}
-string BodyCopier::translateIdentifier(string const& _name)
+YulString BodyCopier::translateIdentifier(YulString _name)
{
if (m_variableReplacements.count(_name))
return m_variableReplacements.at(_name);
diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h
index 5ecfb57a..66ce8e2f 100644
--- a/libyul/optimiser/FullInliner.h
+++ b/libyul/optimiser/FullInliner.h
@@ -77,23 +77,23 @@ public:
/// Inlining heuristic.
/// @param _callSite the name of the function in which the function call is located.
- bool shallInline(FunctionCall const& _funCall, std::string const& _callSite);
+ bool shallInline(FunctionCall const& _funCall, YulString _callSite);
- FunctionDefinition& function(std::string _name) { return *m_functions.at(_name); }
+ FunctionDefinition& function(YulString _name) { return *m_functions.at(_name); }
private:
void updateCodeSize(FunctionDefinition& fun);
- void handleBlock(std::string const& _currentFunctionName, Block& _block);
+ void handleBlock(YulString _currentFunctionName, Block& _block);
/// The AST to be modified. The root block itself will not be modified, because
/// we store pointers to functions.
Block& m_ast;
- std::map<std::string, FunctionDefinition*> m_functions;
+ std::map<YulString, FunctionDefinition*> m_functions;
/// Names of functions to always inline.
- std::set<std::string> m_alwaysInline;
+ std::set<YulString> m_alwaysInline;
/// Variables that are constants (used for inlining heuristic)
- std::set<std::string> m_constants;
- std::map<std::string, size_t> m_functionSizes;
+ std::set<YulString> m_constants;
+ std::map<YulString, size_t> m_functionSizes;
NameDispenser& m_nameDispenser;
};
@@ -104,7 +104,7 @@ private:
class InlineModifier: public ASTModifier
{
public:
- InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, std::string _functionName):
+ InlineModifier(FullInliner& _driver, NameDispenser& _nameDispenser, YulString _functionName):
m_currentFunction(std::move(_functionName)),
m_driver(_driver),
m_nameDispenser(_nameDispenser)
@@ -116,7 +116,7 @@ private:
boost::optional<std::vector<Statement>> tryInlineStatement(Statement& _statement);
std::vector<Statement> performInline(Statement& _statement, FunctionCall& _funCall);
- std::string m_currentFunction;
+ YulString m_currentFunction;
FullInliner& m_driver;
NameDispenser& m_nameDispenser;
};
@@ -131,8 +131,8 @@ class BodyCopier: public ASTCopier
public:
BodyCopier(
NameDispenser& _nameDispenser,
- std::string const& _varNamePrefix,
- std::map<std::string, std::string> const& _variableReplacements
+ YulString _varNamePrefix,
+ std::map<YulString, YulString> const& _variableReplacements
):
m_nameDispenser(_nameDispenser),
m_varNamePrefix(_varNamePrefix),
@@ -144,11 +144,11 @@ public:
virtual Statement operator()(VariableDeclaration const& _varDecl) override;
virtual Statement operator()(FunctionDefinition const& _funDef) override;
- virtual std::string translateIdentifier(std::string const& _name) override;
+ virtual YulString translateIdentifier(YulString _name) override;
NameDispenser& m_nameDispenser;
- std::string const& m_varNamePrefix;
- std::map<std::string, std::string> m_variableReplacements;
+ YulString m_varNamePrefix;
+ std::map<YulString, YulString> m_variableReplacements;
};
diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
index 69dd2095..deaaee97 100644
--- a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
+++ b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
@@ -44,7 +44,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
{
if (_function.returnVariables.size() == 1 && _function.body.statements.size() == 1)
{
- string const& retVariable = _function.returnVariables.front().name;
+ YulString retVariable = _function.returnVariables.front().name;
Statement const& bodyStatement = _function.body.statements.front();
if (bodyStatement.type() == typeid(Assignment))
{
@@ -57,7 +57,7 @@ void InlinableExpressionFunctionFinder::operator()(FunctionDefinition const& _fu
// would not be valid here if we were searching inside a functionally inlinable
// function body.
assertThrow(m_disallowedIdentifiers.empty() && !m_foundDisallowedIdentifier, OptimizerException, "");
- m_disallowedIdentifiers = set<string>{retVariable, _function.name};
+ m_disallowedIdentifiers = set<YulString>{retVariable, _function.name};
boost::apply_visitor(*this, *assignment.value);
if (!m_foundDisallowedIdentifier)
m_inlinableFunctions[_function.name] = &_function;
diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.h b/libyul/optimiser/InlinableExpressionFunctionFinder.h
index 3887e6e5..baf4bbfc 100644
--- a/libyul/optimiser/InlinableExpressionFunctionFinder.h
+++ b/libyul/optimiser/InlinableExpressionFunctionFinder.h
@@ -43,7 +43,7 @@ class InlinableExpressionFunctionFinder: public ASTWalker
{
public:
- std::map<std::string, FunctionDefinition const*> const& inlinableFunctions() const
+ std::map<YulString, FunctionDefinition const*> const& inlinableFunctions() const
{
return m_inlinableFunctions;
}
@@ -54,15 +54,15 @@ public:
virtual void operator()(FunctionDefinition const& _function) override;
private:
- void checkAllowed(std::string const& _name)
+ void checkAllowed(YulString _name)
{
if (m_disallowedIdentifiers.count(_name))
m_foundDisallowedIdentifier = true;
}
bool m_foundDisallowedIdentifier = false;
- std::set<std::string> m_disallowedIdentifiers;
- std::map<std::string, FunctionDefinition const*> m_inlinableFunctions;
+ std::set<YulString> m_disallowedIdentifiers;
+ std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
};
}
diff --git a/libyul/optimiser/MainFunction.cpp b/libyul/optimiser/MainFunction.cpp
index c8f35207..f3306598 100644
--- a/libyul/optimiser/MainFunction.cpp
+++ b/libyul/optimiser/MainFunction.cpp
@@ -40,12 +40,12 @@ void MainFunction::operator()(Block& _block)
for (size_t i = 1; i < _block.statements.size(); ++i)
assertThrow(_block.statements.at(i).type() == typeid(FunctionDefinition), OptimizerException, "");
/// @todo this should handle scopes properly and instead of an assertion it should rename the conflicting function
- assertThrow(NameCollector(_block).names().count("main") == 0, OptimizerException, "");
+ assertThrow(NameCollector(_block).names().count(YulString{"main"}) == 0, OptimizerException, "");
Block& block = boost::get<Block>(_block.statements[0]);
FunctionDefinition main{
block.location,
- "main",
+ YulString{"main"},
{},
{},
std::move(block)
diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp
index b71fa982..36f55b99 100644
--- a/libyul/optimiser/NameCollector.cpp
+++ b/libyul/optimiser/NameCollector.cpp
@@ -29,16 +29,16 @@ using namespace dev::yul;
void NameCollector::operator()(VariableDeclaration const& _varDecl)
{
for (auto const& var: _varDecl.variables)
- m_names.insert(var.name);
+ m_names.emplace(var.name);
}
void NameCollector::operator ()(FunctionDefinition const& _funDef)
{
- m_names.insert(_funDef.name);
+ m_names.emplace(_funDef.name);
for (auto const arg: _funDef.parameters)
- m_names.insert(arg.name);
+ m_names.emplace(arg.name);
for (auto const ret: _funDef.returnVariables)
- m_names.insert(ret.name);
+ m_names.emplace(ret.name);
ASTWalker::operator ()(_funDef);
}
@@ -53,14 +53,14 @@ void ReferencesCounter::operator()(FunctionCall const& _funCall)
ASTWalker::operator()(_funCall);
}
-map<string, size_t> ReferencesCounter::countReferences(Block const& _block)
+map<YulString, size_t> ReferencesCounter::countReferences(Block const& _block)
{
ReferencesCounter counter;
counter(_block);
return counter.references();
}
-map<string, size_t> ReferencesCounter::countReferences(Expression const& _expression)
+map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _expression)
{
ReferencesCounter counter;
counter.visit(_expression);
@@ -70,5 +70,5 @@ map<string, size_t> ReferencesCounter::countReferences(Expression const& _expres
void Assignments::operator()(Assignment const& _assignment)
{
for (auto const& var: _assignment.variableNames)
- m_names.insert(var.name);
+ m_names.emplace(var.name);
}
diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h
index b8f6c1d7..b76eec30 100644
--- a/libyul/optimiser/NameCollector.h
+++ b/libyul/optimiser/NameCollector.h
@@ -22,7 +22,6 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <string>
#include <map>
#include <set>
@@ -46,9 +45,9 @@ public:
virtual void operator()(VariableDeclaration const& _varDecl) override;
virtual void operator()(FunctionDefinition const& _funDef) override;
- std::set<std::string> names() const { return m_names; }
+ std::set<YulString> names() const { return m_names; }
private:
- std::set<std::string> m_names;
+ std::set<YulString> m_names;
};
/**
@@ -61,12 +60,12 @@ public:
virtual void operator()(Identifier const& _identifier);
virtual void operator()(FunctionCall const& _funCall);
- static std::map<std::string, size_t> countReferences(Block const& _block);
- static std::map<std::string, size_t> countReferences(Expression const& _expression);
+ static std::map<YulString, size_t> countReferences(Block const& _block);
+ static std::map<YulString, size_t> countReferences(Expression const& _expression);
- std::map<std::string, size_t> const& references() const { return m_references; }
+ std::map<YulString, size_t> const& references() const { return m_references; }
private:
- std::map<std::string, size_t> m_references;
+ std::map<YulString, size_t> m_references;
};
/**
@@ -78,9 +77,9 @@ public:
using ASTWalker::operator ();
virtual void operator()(Assignment const& _assignment) override;
- std::set<std::string> const& names() const { return m_names; }
+ std::set<YulString> const& names() const { return m_names; }
private:
- std::set<std::string> m_names;
+ std::set<YulString> m_names;
};
}
diff --git a/libyul/optimiser/NameDispenser.cpp b/libyul/optimiser/NameDispenser.cpp
index d3f10bc2..492c863d 100644
--- a/libyul/optimiser/NameDispenser.cpp
+++ b/libyul/optimiser/NameDispenser.cpp
@@ -33,31 +33,31 @@ NameDispenser::NameDispenser(Block const& _ast):
{
}
-NameDispenser::NameDispenser(set<string> _usedNames):
+NameDispenser::NameDispenser(set<YulString> _usedNames):
m_usedNames(std::move(_usedNames))
{
}
-string NameDispenser::newName(string const& _nameHint, string const& _context)
+YulString NameDispenser::newName(YulString _nameHint, YulString _context)
{
// Shortening rules: Use a suffix of _prefix and a prefix of _context.
- string prefix = _nameHint;
+ YulString prefix = _nameHint;
if (!_context.empty())
- prefix = _context.substr(0, 10) + "_" + prefix;
+ prefix = YulString{_context.str().substr(0, 10) + "_" + prefix.str()};
return newNameInternal(prefix);
}
-string NameDispenser::newNameInternal(string const& _nameHint)
+YulString NameDispenser::newNameInternal(YulString _nameHint)
{
+ YulString name = _nameHint;
size_t suffix = 0;
- string name = _nameHint;
while (name.empty() || m_usedNames.count(name))
{
suffix++;
- name = _nameHint + "_" + to_string(suffix);
+ name = YulString(_nameHint.str() + "_" + to_string(suffix));
}
- m_usedNames.insert(name);
+ m_usedNames.emplace(name);
return name;
}
diff --git a/libyul/optimiser/NameDispenser.h b/libyul/optimiser/NameDispenser.h
index 5fbf5f8e..57adbcad 100644
--- a/libyul/optimiser/NameDispenser.h
+++ b/libyul/optimiser/NameDispenser.h
@@ -21,8 +21,9 @@
#include <libyul/ASTDataForward.h>
+#include <libyul/YulString.h>
+
#include <set>
-#include <string>
namespace dev
{
@@ -41,18 +42,18 @@ public:
/// Initialize the name dispenser with all the names used in the given AST.
explicit NameDispenser(Block const& _ast);
/// Initialize the name dispenser with the given used names.
- explicit NameDispenser(std::set<std::string> _usedNames);
+ explicit NameDispenser(std::set<YulString> _usedNames);
/// @returns a currently unused name that should be similar to _nameHint
/// and prefixed by _context if present.
/// If the resulting name would be too long, trims the context at the end
/// and the name hint at the start.
- std::string newName(std::string const& _nameHint, std::string const& _context = {});
+ YulString newName(YulString _nameHint, YulString _context = {});
private:
- std::string newNameInternal(std::string const& _nameHint);
+ YulString newNameInternal(YulString _nameHint);
- std::set<std::string> m_usedNames;
+ std::set<YulString> m_usedNames;
};
}
diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp
index 478858e4..775b7673 100644
--- a/libyul/optimiser/RedundantAssignEliminator.cpp
+++ b/libyul/optimiser/RedundantAssignEliminator.cpp
@@ -44,7 +44,7 @@ void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableD
ASTWalker::operator()(_variableDeclaration);
for (auto const& var: _variableDeclaration.variables)
- m_declaredVariables.insert(var.name);
+ m_declaredVariables.emplace(var.name);
}
void RedundantAssignEliminator::operator()(Assignment const& _assignment)
@@ -156,7 +156,7 @@ void RedundantAssignEliminator::run(Block& _ast)
{
assertThrow(assignment.second != State::Undecided, OptimizerException, "");
if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable())
- assignmentsToRemove.insert(assignment.first);
+ assignmentsToRemove.emplace(assignment.first);
}
AssignmentRemover remover{assignmentsToRemove};
@@ -176,7 +176,7 @@ void RedundantAssignEliminator::join(RedundantAssignEliminator& _other)
m_assignments[var.first] = std::move(var.second);
}
-void RedundantAssignEliminator::changeUndecidedTo(string const& _variable, RedundantAssignEliminator::State _newState)
+void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
{
for (auto& assignment: m_assignments[_variable])
if (assignment.second == State{State::Undecided})
diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h
index 52092138..805a1f63 100644
--- a/libyul/optimiser/RedundantAssignEliminator.h
+++ b/libyul/optimiser/RedundantAssignEliminator.h
@@ -125,9 +125,9 @@ private:
public:
enum Value { Unused, Undecided, Used };
State(Value _value = Undecided): m_value(_value) {}
- bool operator==(State _other) const { return m_value == _other.m_value; }
- bool operator!=(State _other) const { return !operator==(_other); }
- void join(State _other)
+ inline bool operator==(State _other) const { return m_value == _other.m_value; }
+ inline bool operator!=(State _other) const { return !operator==(_other); }
+ inline void join(State const& _other)
{
// Using "max" works here because of the order of the values in the enum.
m_value = Value(std::max(int(_other.m_value), int(m_value)));
@@ -156,17 +156,18 @@ private:
private:
RedundantAssignEliminator& m_rae;
- std::set<std::string> m_outerDeclaredVariables;
+ std::set<YulString> m_outerDeclaredVariables;
};
/// Joins the assignment mapping with @a _other according to the rules laid out
/// above.
/// Will destroy @a _other.
void join(RedundantAssignEliminator& _other);
- void changeUndecidedTo(std::string const& _variable, State _newState);
+ void changeUndecidedTo(YulString _variable, State _newState);
- std::set<std::string> m_declaredVariables;
- std::map<std::string, std::map<Assignment const*, State>> m_assignments;
+ std::set<YulString> m_declaredVariables;
+ // TODO check that this does not cause nondeterminism!
+ std::map<YulString, std::map<Assignment const*, State>> m_assignments;
};
class AssignmentRemover: public ASTModifier
diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp
index a99db0b6..38d50ef4 100644
--- a/libyul/optimiser/Rematerialiser.cpp
+++ b/libyul/optimiser/Rematerialiser.cpp
@@ -37,7 +37,7 @@ void Rematerialiser::visit(Expression& _e)
Identifier& identifier = boost::get<Identifier>(_e);
if (m_value.count(identifier.name))
{
- string name = identifier.name;
+ YulString name = identifier.name;
for (auto const& ref: m_references[name])
assertThrow(inScope(ref), OptimizerException, "");
assertThrow(m_value.at(name), OptimizerException, "");
diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h
index afcfab3e..f82465eb 100644
--- a/libyul/optimiser/Rematerialiser.h
+++ b/libyul/optimiser/Rematerialiser.h
@@ -22,10 +22,6 @@
#include <libyul/optimiser/DataFlowAnalyzer.h>
-#include <string>
-#include <map>
-#include <set>
-
namespace dev
{
namespace yul
diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp
index 9db7bd03..f209ee7b 100644
--- a/libyul/optimiser/SSATransform.cpp
+++ b/libyul/optimiser/SSATransform.cpp
@@ -62,15 +62,15 @@ void SSATransform::operator()(ForLoop& _for)
void SSATransform::operator()(Block& _block)
{
- set<string> variablesToClearAtEnd;
+ set<YulString> variablesToClearAtEnd;
// Creates a new variable (and returns its declaration) with value _value
// and replaces _value by a reference to that new variable.
- auto replaceByNew = [&](SourceLocation _loc, string _varName, string _type, shared_ptr<Expression>& _value) -> VariableDeclaration
+ auto replaceByNew = [&](SourceLocation _loc, YulString _varName, YulString _type, shared_ptr<Expression>& _value) -> VariableDeclaration
{
- string newName = m_nameDispenser.newName(_varName);
+ YulString newName = m_nameDispenser.newName(_varName);
m_currentVariableValues[_varName] = newName;
- variablesToClearAtEnd.insert(_varName);
+ variablesToClearAtEnd.emplace(_varName);
shared_ptr<Expression> v = make_shared<Expression>(Identifier{_loc, newName});
_value.swap(v);
return VariableDeclaration{_loc, {TypedName{_loc, std::move(newName), std::move(_type)}}, std::move(v)};
diff --git a/libyul/optimiser/SSATransform.h b/libyul/optimiser/SSATransform.h
index 2adc657d..bb642549 100644
--- a/libyul/optimiser/SSATransform.h
+++ b/libyul/optimiser/SSATransform.h
@@ -85,13 +85,13 @@ public:
static void run(Block& _ast, NameDispenser& _nameDispenser);
private:
- explicit SSATransform(NameDispenser& _nameDispenser, std::set<std::string> const& _variablesToReplace):
+ explicit SSATransform(NameDispenser& _nameDispenser, std::set<YulString> const& _variablesToReplace):
m_nameDispenser(_nameDispenser), m_variablesToReplace(_variablesToReplace)
{ }
NameDispenser& m_nameDispenser;
- std::set<std::string> const& m_variablesToReplace;
- std::map<std::string, std::string> m_currentVariableValues;
+ std::set<YulString> const& m_variablesToReplace;
+ std::map<YulString, YulString> m_currentVariableValues;
};
}
diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp
index a1291d67..491117da 100644
--- a/libyul/optimiser/SSAValueTracker.cpp
+++ b/libyul/optimiser/SSAValueTracker.cpp
@@ -42,7 +42,7 @@ void SSAValueTracker::operator()(VariableDeclaration const& _varDecl)
setValue(var.name, nullptr);
}
-void SSAValueTracker::setValue(string const& _name, Expression const* _value)
+void SSAValueTracker::setValue(YulString _name, Expression const* _value)
{
assertThrow(
m_values.count(_name) == 0,
diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h
index 8c39a98e..d1539c86 100644
--- a/libyul/optimiser/SSAValueTracker.h
+++ b/libyul/optimiser/SSAValueTracker.h
@@ -23,7 +23,6 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <string>
#include <map>
#include <set>
@@ -45,13 +44,13 @@ public:
virtual void operator()(VariableDeclaration const& _varDecl) override;
virtual void operator()(Assignment const& _assignment) override;
- std::map<std::string, Expression const*> const& values() const { return m_values; }
- Expression const* value(std::string const& _name) const { return m_values.at(_name); }
+ std::map<YulString, Expression const*> const& values() const { return m_values; }
+ Expression const* value(YulString _name) const { return m_values.at(_name); }
private:
- void setValue(std::string const& _name, Expression const* _value);
+ void setValue(YulString _name, Expression const* _value);
- std::map<std::string, Expression const*> m_values;
+ std::map<YulString, Expression const*> m_values;
};
}
diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp
index 33f3af77..3c49016e 100644
--- a/libyul/optimiser/Semantics.cpp
+++ b/libyul/optimiser/Semantics.cpp
@@ -40,7 +40,7 @@ MovableChecker::MovableChecker(Expression const& _expression)
void MovableChecker::operator()(Identifier const& _identifier)
{
ASTWalker::operator()(_identifier);
- m_variableReferences.insert(_identifier.name);
+ m_variableReferences.emplace(_identifier.name);
}
void MovableChecker::operator()(FunctionalInstruction const& _instr)
diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h
index 1caa12fb..620a91cb 100644
--- a/libyul/optimiser/Semantics.h
+++ b/libyul/optimiser/Semantics.h
@@ -22,8 +22,6 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <string>
-#include <map>
#include <set>
namespace dev
@@ -49,11 +47,11 @@ public:
using ASTWalker::visit;
bool movable() const { return m_movable; }
- std::set<std::string> const& referencedVariables() const { return m_variableReferences; }
+ std::set<YulString> const& referencedVariables() const { return m_variableReferences; }
private:
/// Which variables the current expression references.
- std::set<std::string> m_variableReferences;
+ std::set<YulString> m_variableReferences;
/// Is the current expression movable or not.
bool m_movable = true;
};
diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp
index aca943b0..5721042f 100644
--- a/libyul/optimiser/SimplificationRules.cpp
+++ b/libyul/optimiser/SimplificationRules.cpp
@@ -36,7 +36,7 @@ using namespace dev::yul;
SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
Expression const& _expr,
- map<string, Expression const*> const& _ssaValues
+ map<YulString, Expression const*> const& _ssaValues
)
{
if (_expr.type() != typeid(FunctionalInstruction))
@@ -46,7 +46,7 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
FunctionalInstruction const& instruction = boost::get<FunctionalInstruction>(_expr);
- for (auto const& rule: rules.m_rules[byte(instruction.instruction)])
+ for (auto const& rule: rules.m_rules[uint8_t(instruction.instruction)])
{
rules.resetMatchGroups();
if (rule.pattern.matches(_expr, _ssaValues))
@@ -57,7 +57,7 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
bool SimplificationRules::isInitialized() const
{
- return !m_rules[byte(solidity::Instruction::ADD)].empty();
+ return !m_rules[uint8_t(solidity::Instruction::ADD)].empty();
}
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules)
@@ -68,7 +68,7 @@ void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _r
void SimplificationRules::addRule(SimplificationRule<Pattern> const& _rule)
{
- m_rules[byte(_rule.pattern.instruction())].push_back(_rule);
+ m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule);
}
SimplificationRules::SimplificationRules()
@@ -104,7 +104,7 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _
m_matchGroups = &_matchGroups;
}
-bool Pattern::matches(Expression const& _expr, map<string, Expression const*> const& _ssaValues) const
+bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*> const& _ssaValues) const
{
Expression const* expr = &_expr;
@@ -112,7 +112,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co
// Do not do it for "Any" because we can check identity better for variables.
if (m_kind != PatternKind::Any && _expr.type() == typeid(Identifier))
{
- string const& varName = boost::get<Identifier>(_expr).name;
+ YulString varName = boost::get<Identifier>(_expr).name;
if (_ssaValues.count(varName))
expr = _ssaValues.at(varName);
}
@@ -125,7 +125,7 @@ bool Pattern::matches(Expression const& _expr, map<string, Expression const*> co
Literal const& literal = boost::get<Literal>(*expr);
if (literal.kind != assembly::LiteralKind::Number)
return false;
- if (m_data && *m_data != u256(literal.value))
+ if (m_data && *m_data != u256(literal.value.str()))
return false;
assertThrow(m_arguments.empty(), OptimizerException, "");
}
@@ -193,7 +193,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
if (m_kind == PatternKind::Constant)
{
assertThrow(m_data, OptimizerException, "No match group and no constant value given.");
- return Literal{_location, assembly::LiteralKind::Number, formatNumber(*m_data), ""};
+ return Literal{_location, assembly::LiteralKind::Number, YulString{formatNumber(*m_data)}, {}};
}
else if (m_kind == PatternKind::Operation)
{
@@ -209,8 +209,8 @@ u256 Pattern::d() const
{
Literal const& literal = boost::get<Literal>(matchGroupValue());
assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, "");
- assertThrow(isValidDecimal(literal.value) || isValidHex(literal.value), OptimizerException, "");
- return u256(literal.value);
+ assertThrow(isValidDecimal(literal.value.str()) || isValidHex(literal.value.str()), OptimizerException, "");
+ return u256(literal.value.str());
}
Expression const& Pattern::matchGroupValue() const
diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h
index 82ae5d22..b608ca91 100644
--- a/libyul/optimiser/SimplificationRules.h
+++ b/libyul/optimiser/SimplificationRules.h
@@ -52,7 +52,7 @@ public:
/// @param _ssaValues values of variables that are assigned exactly once.
static SimplificationRule<Pattern> const* findFirstMatch(
Expression const& _expr,
- std::map<std::string, Expression const*> const& _ssaValues
+ std::map<YulString, Expression const*> const& _ssaValues
);
/// Checks whether the rulelist is non-empty. This is usually enforced
@@ -96,7 +96,7 @@ public:
/// same expression equivalence class.
void setMatchGroup(unsigned _group, std::map<unsigned, Expression const*>& _matchGroups);
unsigned matchGroup() const { return m_matchGroup; }
- bool matches(Expression const& _expr, std::map<std::string, Expression const*> const& _ssaValues) const;
+ bool matches(Expression const& _expr, std::map<YulString, Expression const*> const& _ssaValues) const;
std::vector<Pattern> arguments() const { return m_arguments; }
diff --git a/libyul/optimiser/Substitution.cpp b/libyul/optimiser/Substitution.cpp
index 4a000a85..9b3d4c03 100644
--- a/libyul/optimiser/Substitution.cpp
+++ b/libyul/optimiser/Substitution.cpp
@@ -30,7 +30,7 @@ Expression Substitution::translate(Expression const& _expression)
{
if (_expression.type() == typeid(Identifier))
{
- string const& name = boost::get<Identifier>(_expression).name;
+ YulString name = boost::get<Identifier>(_expression).name;
if (m_substitutions.count(name))
// No recursive substitution
return ASTCopier().translate(*m_substitutions.at(name));
diff --git a/libyul/optimiser/Substitution.h b/libyul/optimiser/Substitution.h
index b734cdca..59ee4620 100644
--- a/libyul/optimiser/Substitution.h
+++ b/libyul/optimiser/Substitution.h
@@ -22,9 +22,9 @@
#include <libyul/optimiser/ASTCopier.h>
-#include <string>
+#include <libyul/YulString.h>
+
#include <map>
-#include <set>
namespace dev
{
@@ -37,13 +37,13 @@ namespace yul
class Substitution: public ASTCopier
{
public:
- Substitution(std::map<std::string, Expression const*> const& _substitutions):
+ Substitution(std::map<YulString, Expression const*> const& _substitutions):
m_substitutions(_substitutions)
{}
virtual Expression translate(Expression const& _expression) override;
private:
- std::map<std::string, Expression const*> const& m_substitutions;
+ std::map<YulString, Expression const*> const& m_substitutions;
};
}
diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp
index 5b325afd..c7339d2e 100644
--- a/libyul/optimiser/Suite.cpp
+++ b/libyul/optimiser/Suite.cpp
@@ -48,10 +48,10 @@ using namespace dev::yul;
void OptimiserSuite::run(
Block& _ast,
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
- set<string> const& _externallyUsedIdentifiers
+ set<YulString> const& _externallyUsedIdentifiers
)
{
- set<string> reservedIdentifiers = _externallyUsedIdentifiers;
+ set<YulString> reservedIdentifiers = _externallyUsedIdentifiers;
Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast));
diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h
index bb6274bd..5b564c56 100644
--- a/libyul/optimiser/Suite.h
+++ b/libyul/optimiser/Suite.h
@@ -21,9 +21,8 @@
#pragma once
#include <libyul/ASTDataForward.h>
+#include <libyul/YulString.h>
-#include <string>
-#include <map>
#include <set>
namespace dev
@@ -47,7 +46,8 @@ public:
static void run(
Block& _ast,
solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
- std::set<std::string> const& _externallyUsedIdentifiers = std::set<std::string>()
+
+ std::set<YulString> const& _externallyUsedIdentifiers = {}
);
};
diff --git a/libyul/optimiser/SyntacticalEquality.cpp b/libyul/optimiser/SyntacticalEquality.cpp
index f22b5c31..66912383 100644
--- a/libyul/optimiser/SyntacticalEquality.cpp
+++ b/libyul/optimiser/SyntacticalEquality.cpp
@@ -34,6 +34,7 @@ bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const&
{
if (_e1.type() != _e2.type())
return false;
+ // TODO This somehow calls strcmp - WHERE?
// TODO This should be replaced by some kind of AST walker as soon as it gets
// more complex.
diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp
index 37a74553..a7b32873 100644
--- a/libyul/optimiser/UnusedPruner.cpp
+++ b/libyul/optimiser/UnusedPruner.cpp
@@ -33,7 +33,7 @@ using namespace std;
using namespace dev;
using namespace dev::yul;
-UnusedPruner::UnusedPruner(Block& _ast, set<string> const& _externallyUsedFunctions)
+UnusedPruner::UnusedPruner(Block& _ast, set<YulString> const& _externallyUsedFunctions)
{
ReferencesCounter counter;
counter(_ast);
@@ -91,7 +91,7 @@ void UnusedPruner::operator()(Block& _block)
ASTModifier::operator()(_block);
}
-void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externallyUsedFunctions)
+void UnusedPruner::runUntilStabilised(Block& _ast, set<YulString> const& _externallyUsedFunctions)
{
while (true)
{
@@ -102,12 +102,12 @@ void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externall
}
}
-bool UnusedPruner::used(string const& _name) const
+bool UnusedPruner::used(YulString _name) const
{
return m_references.count(_name) && m_references.at(_name) > 0;
}
-void UnusedPruner::subtractReferences(map<string, size_t> const& _subtrahend)
+void UnusedPruner::subtractReferences(map<YulString, size_t> const& _subtrahend)
{
for (auto const& ref: _subtrahend)
{
diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h
index 30617ff3..2dd74940 100644
--- a/libyul/optimiser/UnusedPruner.h
+++ b/libyul/optimiser/UnusedPruner.h
@@ -21,8 +21,8 @@
#pragma once
#include <libyul/optimiser/ASTWalker.h>
+#include <libyul/YulString.h>
-#include <string>
#include <map>
#include <set>
@@ -44,7 +44,7 @@ namespace yul
class UnusedPruner: public ASTModifier
{
public:
- explicit UnusedPruner(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
+ explicit UnusedPruner(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {});
using ASTModifier::operator();
virtual void operator()(Block& _block) override;
@@ -53,14 +53,14 @@ public:
bool shouldRunAgain() const { return m_shouldRunAgain; }
// Run the pruner until the code does not change anymore.
- static void runUntilStabilised(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
+ static void runUntilStabilised(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {});
private:
- bool used(std::string const& _name) const;
- void subtractReferences(std::map<std::string, size_t> const& _subtrahend);
+ bool used(YulString _name) const;
+ void subtractReferences(std::map<YulString, size_t> const& _subtrahend);
bool m_shouldRunAgain = false;
- std::map<std::string, size_t> m_references;
+ std::map<YulString, size_t> m_references;
};
}
diff --git a/libyul/optimiser/VarDeclPropagator.cpp b/libyul/optimiser/VarDeclPropagator.cpp
new file mode 100644
index 00000000..537b7020
--- /dev/null
+++ b/libyul/optimiser/VarDeclPropagator.cpp
@@ -0,0 +1,129 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libyul/optimiser/VarDeclPropagator.h>
+#include <libsolidity/inlineasm/AsmData.h>
+#include <libdevcore/CommonData.h>
+#include <boost/range/algorithm_ext/erase.hpp>
+#include <algorithm>
+#include <map>
+
+using namespace std;
+using namespace dev;
+using namespace dev::yul;
+
+using dev::solidity::assembly::TypedName;
+using dev::solidity::assembly::TypedNameList;
+
+void VarDeclPropagator::operator()(Block& _block)
+{
+ map<YulString, TypedName> outerEmptyVarDecls;
+ map<YulString, TypedName> outerLazyInitializedVarDecls;
+ swap(m_emptyVarDecls, outerEmptyVarDecls);
+ swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls);
+
+ ASTModifier::operator()(_block);
+
+ iterateReplacing(
+ _block.statements,
+ [this](Statement& _stmt) -> boost::optional<vector<Statement>>
+ {
+ if (_stmt.type() == typeid(VariableDeclaration))
+ {
+ VariableDeclaration& varDecl = boost::get<VariableDeclaration>(_stmt);
+ boost::remove_erase_if(
+ varDecl.variables,
+ [&](TypedName const& _typedName) { return m_lazyInitializedVarDecls.count(_typedName.name); }
+ );
+ if (varDecl.variables.empty())
+ return vector<Statement>{};
+ else
+ return {};
+ }
+ else if (_stmt.type() == typeid(Assignment))
+ {
+ Assignment& assignment = boost::get<Assignment>(_stmt);
+ if (isFullyLazyInitialized(assignment.variableNames))
+ return vector<Statement>{recreateVariableDeclaration(assignment)};
+ else
+ return {};
+ }
+ else
+ return {};
+ }
+ );
+
+ swap(m_emptyVarDecls, outerEmptyVarDecls);
+ swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls);
+}
+
+void VarDeclPropagator::operator()(VariableDeclaration& _varDecl)
+{
+ if (_varDecl.value)
+ visit(*_varDecl.value);
+ else
+ for (TypedName const& typedName: _varDecl.variables)
+ m_emptyVarDecls[typedName.name] = typedName;
+}
+
+void VarDeclPropagator::operator()(Assignment& _assignment)
+{
+ visit(*_assignment.value);
+
+ if (allVarNamesUninitialized(_assignment.variableNames))
+ for (Identifier const& ident: _assignment.variableNames)
+ m_lazyInitializedVarDecls[ident.name] = m_emptyVarDecls[ident.name];
+
+ for (Identifier& name: _assignment.variableNames)
+ (*this)(name);
+}
+
+void VarDeclPropagator::operator()(Identifier& _ident)
+{
+ m_emptyVarDecls.erase(_ident.name);
+}
+
+bool VarDeclPropagator::allVarNamesUninitialized(vector<Identifier> const& _variableNames) const
+{
+ return all_of(
+ begin(_variableNames),
+ end(_variableNames),
+ [&](Identifier const& _ident) -> bool { return m_emptyVarDecls.count(_ident.name); }
+ );
+}
+
+bool VarDeclPropagator::isFullyLazyInitialized(vector<Identifier> const& _variableNames) const
+{
+ return all_of(
+ begin(_variableNames),
+ end(_variableNames),
+ [&](Identifier const& ident) -> bool { return m_lazyInitializedVarDecls.count(ident.name); }
+ );
+}
+
+VariableDeclaration VarDeclPropagator::recreateVariableDeclaration(Assignment& _assignment)
+{
+ TypedNameList variables;
+
+ for (Identifier const& varName: _assignment.variableNames)
+ {
+ variables.emplace_back(move(m_lazyInitializedVarDecls.at(varName.name)));
+ m_lazyInitializedVarDecls.erase(varName.name);
+ }
+
+ return VariableDeclaration{move(_assignment.location), move(variables), std::move(_assignment.value)};
+}
diff --git a/libyul/optimiser/VarDeclPropagator.h b/libyul/optimiser/VarDeclPropagator.h
new file mode 100644
index 00000000..4522d23a
--- /dev/null
+++ b/libyul/optimiser/VarDeclPropagator.h
@@ -0,0 +1,63 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <libyul/ASTDataForward.h>
+#include <libyul/optimiser/ASTWalker.h>
+#include <libyul/Exceptions.h>
+#include <libsolidity/inlineasm/AsmDataForward.h>
+#include <vector>
+#include <set>
+#include <map>
+
+namespace dev
+{
+namespace yul
+{
+
+/**
+ * Rewrites Assignment statements into VariableDeclaration when the assignment's LHS
+ * variables had no value yet.
+ *
+ * It recursively walks through the AST and moves each declaration of variables to
+ * the first assignment within the same block (if possible)..
+ */
+class VarDeclPropagator: public ASTModifier
+{
+public:
+ using ASTModifier::operator();
+ void operator()(Block& _block) override;
+ void operator()(VariableDeclaration& _varDecl) override;
+ void operator()(Assignment& _assignment) override;
+ void operator()(Identifier& _ident) override;
+
+private:
+ bool allVarNamesUninitialized(std::vector<Identifier> const& _variableNames) const;
+ bool isFullyLazyInitialized(std::vector<Identifier> const& _variableNames) const;
+ VariableDeclaration recreateVariableDeclaration(Assignment& _assignment);
+
+private:
+ /// Holds a list of variables from current Block that have no value assigned yet.
+ std::map<YulString, TypedName> m_emptyVarDecls;
+
+ /// Holds a list variables (and their TypedName) within the current block.
+ std::map<YulString, TypedName> m_lazyInitializedVarDecls;
+};
+
+}
+}
diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh
index 1cfbf716..36a8ef7f 100755
--- a/scripts/release_ppa.sh
+++ b/scripts/release_ppa.sh
@@ -54,7 +54,7 @@ keyid=70D110489D66E2F6
email=builds@ethereum.org
packagename=solc
-for distribution in trusty xenial artful bionic
+for distribution in trusty xenial bionic cosmic
do
cd /tmp/
rm -rf $distribution
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index 0b42f9d0..e275147b 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -147,11 +147,11 @@ public:
static std::pair<bool, std::string> compareAndCreateMessage(bytes const& _result, bytes const& _expectation);
- static bytes encode(bool _value) { return encode(byte(_value)); }
+ static bytes encode(bool _value) { return encode(uint8_t(_value)); }
static bytes encode(int _value) { return encode(u256(_value)); }
static bytes encode(size_t _value) { return encode(u256(_value)); }
static bytes encode(char const* _value) { return encode(std::string(_value)); }
- static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; }
+ static bytes encode(uint8_t _value) { return bytes(31, 0) + bytes{_value}; }
static bytes encode(u256 const& _value) { return toBigEndian(_value); }
/// @returns the fixed-point encoding of a rational number with a given
/// number of fractional bits.
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 8d17e56f..87646737 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1259,14 +1259,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test)
}
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(0));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(0));
- ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x1234), encodeArgs());
- ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x01), 0x8765), encodeArgs());
- ABI_CHECK(callContractFunction("get(uint8)", byte( 0x00)), encodeArgs(0x1234));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(0x8765));
- ABI_CHECK(callContractFunction("set(uint8,uint256)", byte(0x00), 0x3), encodeArgs());
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(0x3));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0));
+ ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x1234), encodeArgs());
+ ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x01), 0x8765), encodeArgs());
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t( 0x00)), encodeArgs(0x1234));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0x8765));
+ ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x3), encodeArgs());
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0x3));
}
BOOST_AUTO_TEST_CASE(compound_assign)
@@ -1321,21 +1321,21 @@ BOOST_AUTO_TEST_CASE(simple_mapping)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("get(uint8)", byte(0)), encodeArgs(byte(0x00)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0x00)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00)));
- callContractFunction("set(uint8,uint8)", byte(0x01), byte(0xa1));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0x00)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0xa1)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00)));
- callContractFunction("set(uint8,uint8)", byte(0x00), byte(0xef));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0xef)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0xa1)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00)));
- callContractFunction("set(uint8,uint8)", byte(0x01), byte(0x05));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x00)), encodeArgs(byte(0xef)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0x01)), encodeArgs(byte(0x05)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(0xa7)), encodeArgs(byte(0x00)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0)), encodeArgs(uint8_t(0x00)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x00)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
+ callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0xa1));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0x00)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
+ callContractFunction("set(uint8,uint8)", uint8_t(0x00), uint8_t(0xef));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
+ callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0x05));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x05)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
}
BOOST_AUTO_TEST_CASE(mapping_state)
@@ -1496,7 +1496,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_assignment)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21)));
}
BOOST_AUTO_TEST_CASE(mapping_local_tuple_assignment)
@@ -1519,7 +1519,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_tuple_assignment)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21)));
}
BOOST_AUTO_TEST_CASE(mapping_local_compound_assignment)
@@ -1540,7 +1540,7 @@ BOOST_AUTO_TEST_CASE(mapping_local_compound_assignment)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("f()"), encodeArgs(byte(42), byte(0), byte(0), byte(21)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(21)));
}
BOOST_AUTO_TEST_CASE(mapping_internal_argument)
@@ -1565,10 +1565,10 @@ BOOST_AUTO_TEST_CASE(mapping_internal_argument)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", byte(1), byte(21), byte(42)), encodeArgs(byte(0), byte(0)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(21), byte(42)));
- ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", byte(1), byte(10), byte(11)), encodeArgs(byte(21), byte(42)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(10), byte(11)));
+ ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", uint8_t(1), uint8_t(21), uint8_t(42)), encodeArgs(uint8_t(0), uint8_t(0)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(21), uint8_t(42)));
+ ABI_CHECK(callContractFunction("set(uint8,uint8,uint8)", uint8_t(1), uint8_t(10), uint8_t(11)), encodeArgs(uint8_t(21), uint8_t(42)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(10), uint8_t(11)));
}
BOOST_AUTO_TEST_CASE(mapping_array_internal_argument)
@@ -1595,10 +1595,10 @@ BOOST_AUTO_TEST_CASE(mapping_array_internal_argument)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", byte(1), byte(21), byte(22), byte(42), byte(43)), encodeArgs(byte(0), byte(0), byte(0), byte(0)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(21), byte(22), byte(42), byte(43)));
- ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", byte(1), byte(10), byte(30), byte(11), byte(31)), encodeArgs(byte(21), byte(22), byte(42), byte(43)));
- ABI_CHECK(callContractFunction("get(uint8)", byte(1)), encodeArgs(byte(10), byte(30), byte(11), byte(31)));
+ ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", uint8_t(1), uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43)), encodeArgs(uint8_t(0), uint8_t(0), uint8_t(0), uint8_t(0)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43)));
+ ABI_CHECK(callContractFunction("set(uint8,uint8,uint8,uint8,uint8)", uint8_t(1), uint8_t(10), uint8_t(30), uint8_t(11), uint8_t(31)), encodeArgs(uint8_t(21), uint8_t(22), uint8_t(42), uint8_t(43)));
+ ABI_CHECK(callContractFunction("get(uint8)", uint8_t(1)), encodeArgs(uint8_t(10), uint8_t(30), uint8_t(11), uint8_t(31)));
}
BOOST_AUTO_TEST_CASE(mapping_internal_return)
@@ -1626,8 +1626,8 @@ BOOST_AUTO_TEST_CASE(mapping_internal_return)
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("g()"), encodeArgs(byte(0), byte(42), byte(0), byte(0), byte(84), byte (21)));
- ABI_CHECK(callContractFunction("h()"), encodeArgs(byte(0), byte(42), byte(0), byte(0), byte(84), byte (17)));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(uint8_t(0), uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(84), uint8_t (21)));
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(uint8_t(0), uint8_t(42), uint8_t(0), uint8_t(0), uint8_t(84), uint8_t (17)));
}
BOOST_AUTO_TEST_CASE(structs)
@@ -1819,7 +1819,7 @@ BOOST_AUTO_TEST_CASE(constructor)
}
)";
compileAndRun(sourceCode);
- map<u256, byte> data;
+ map<u256, uint8_t> data;
data[7] = 8;
auto get = [&](u256 const& _x) -> u256
{
@@ -2624,7 +2624,7 @@ BOOST_AUTO_TEST_CASE(ecrecover)
)";
compileAndRun(sourceCode);
u256 h("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c");
- byte v = 28;
+ uint8_t v = 28;
u256 r("0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f");
u256 s("0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549");
u160 addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b");
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index 26b7914f..309cbf0b 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -180,7 +180,7 @@ BOOST_AUTO_TEST_CASE(literal_true)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH1), 0x1});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(literal_false)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH1), 0x0});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x0});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(int_literal)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
+ bytes expectation({uint8_t(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90,
0x12, 0x34, 0x56, 0x78, 0x90});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH1), 0x1});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x1});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00});
+ bytes expectation({uint8_t(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00});
+ bytes expectation({uint8_t(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -268,7 +268,7 @@ BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
+ bytes expectation({uint8_t(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -281,12 +281,12 @@ BOOST_AUTO_TEST_CASE(comparison)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH1), 0x1, byte(Instruction::ISZERO), byte(Instruction::ISZERO),
- byte(Instruction::PUSH2), 0x11, 0xaa,
- byte(Instruction::PUSH2), 0x10, 0xaa,
- byte(Instruction::LT), byte(Instruction::ISZERO), byte(Instruction::ISZERO),
- byte(Instruction::EQ),
- byte(Instruction::ISZERO)});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::PUSH2), 0x11, 0xaa,
+ uint8_t(Instruction::PUSH2), 0x10, 0xaa,
+ uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::EQ),
+ uint8_t(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -299,23 +299,23 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation({byte(Instruction::PUSH1), 0x12, // 8 + 10
- byte(Instruction::PUSH1), 0x4,
- byte(Instruction::GT),
- byte(Instruction::ISZERO), // after this we have 4 <= 8 + 10
- byte(Instruction::DUP1),
- byte(Instruction::PUSH1), 0x11,
- byte(Instruction::JUMPI), // short-circuit if it is true
- byte(Instruction::POP),
- byte(Instruction::PUSH1), 0x2,
- byte(Instruction::PUSH1), 0x9,
- byte(Instruction::EQ),
- byte(Instruction::ISZERO), // after this we have 9 != 2
- byte(Instruction::JUMPDEST),
- byte(Instruction::ISZERO), byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x1, byte(Instruction::ISZERO), byte(Instruction::ISZERO),
- byte(Instruction::EQ),
- byte(Instruction::ISZERO)});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x12, // 8 + 10
+ uint8_t(Instruction::PUSH1), 0x4,
+ uint8_t(Instruction::GT),
+ uint8_t(Instruction::ISZERO), // after this we have 4 <= 8 + 10
+ uint8_t(Instruction::DUP1),
+ uint8_t(Instruction::PUSH1), 0x11,
+ uint8_t(Instruction::JUMPI), // short-circuit if it is true
+ uint8_t(Instruction::POP),
+ uint8_t(Instruction::PUSH1), 0x2,
+ uint8_t(Instruction::PUSH1), 0x9,
+ uint8_t(Instruction::EQ),
+ uint8_t(Instruction::ISZERO), // after this we have 9 != 2
+ uint8_t(Instruction::JUMPDEST),
+ uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::EQ),
+ uint8_t(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -327,37 +327,37 @@ BOOST_AUTO_TEST_CASE(arithmetic)
}
)";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
- bytes expectation({byte(Instruction::PUSH1), 0x1,
- byte(Instruction::PUSH1), 0x2,
- byte(Instruction::PUSH1), 0x3,
- byte(Instruction::PUSH1), 0x4,
- byte(Instruction::PUSH1), 0x5,
- byte(Instruction::PUSH1), 0x6,
- byte(Instruction::PUSH1), 0x7,
- byte(Instruction::PUSH1), 0x8,
- byte(Instruction::DUP9),
- byte(Instruction::XOR),
- byte(Instruction::AND),
- byte(Instruction::OR),
- byte(Instruction::SUB),
- byte(Instruction::ADD),
- byte(Instruction::DUP2),
- byte(Instruction::ISZERO),
- byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x1d,
- byte(Instruction::JUMPI),
- byte(Instruction::INVALID),
- byte(Instruction::JUMPDEST),
- byte(Instruction::MOD),
- byte(Instruction::DUP2),
- byte(Instruction::ISZERO),
- byte(Instruction::ISZERO),
- byte(Instruction::PUSH1), 0x26,
- byte(Instruction::JUMPI),
- byte(Instruction::INVALID),
- byte(Instruction::JUMPDEST),
- byte(Instruction::DIV),
- byte(Instruction::MUL)});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x1,
+ uint8_t(Instruction::PUSH1), 0x2,
+ uint8_t(Instruction::PUSH1), 0x3,
+ uint8_t(Instruction::PUSH1), 0x4,
+ uint8_t(Instruction::PUSH1), 0x5,
+ uint8_t(Instruction::PUSH1), 0x6,
+ uint8_t(Instruction::PUSH1), 0x7,
+ uint8_t(Instruction::PUSH1), 0x8,
+ uint8_t(Instruction::DUP9),
+ uint8_t(Instruction::XOR),
+ uint8_t(Instruction::AND),
+ uint8_t(Instruction::OR),
+ uint8_t(Instruction::SUB),
+ uint8_t(Instruction::ADD),
+ uint8_t(Instruction::DUP2),
+ uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::PUSH1), 0x1d,
+ uint8_t(Instruction::JUMPI),
+ uint8_t(Instruction::INVALID),
+ uint8_t(Instruction::JUMPDEST),
+ uint8_t(Instruction::MOD),
+ uint8_t(Instruction::DUP2),
+ uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::ISZERO),
+ uint8_t(Instruction::PUSH1), 0x26,
+ uint8_t(Instruction::JUMPI),
+ uint8_t(Instruction::INVALID),
+ uint8_t(Instruction::JUMPDEST),
+ uint8_t(Instruction::DIV),
+ uint8_t(Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -370,13 +370,13 @@ BOOST_AUTO_TEST_CASE(unary_operators)
)";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
- bytes expectation({byte(Instruction::PUSH1), 0x2,
- byte(Instruction::DUP2),
- byte(Instruction::PUSH1), 0x0,
- byte(Instruction::SUB),
- byte(Instruction::NOT),
- byte(Instruction::EQ),
- byte(Instruction::ISZERO)});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x2,
+ uint8_t(Instruction::DUP2),
+ uint8_t(Instruction::PUSH1), 0x0,
+ uint8_t(Instruction::SUB),
+ uint8_t(Instruction::NOT),
+ uint8_t(Instruction::EQ),
+ uint8_t(Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -390,47 +390,47 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}});
// Stack: a, x
- bytes expectation({byte(Instruction::DUP2),
- byte(Instruction::DUP1),
- byte(Instruction::PUSH1), 0x1,
- byte(Instruction::ADD),
+ bytes expectation({uint8_t(Instruction::DUP2),
+ uint8_t(Instruction::DUP1),
+ uint8_t(Instruction::PUSH1), 0x1,
+ uint8_t(Instruction::ADD),
// Stack here: a x a (a+1)
- byte(Instruction::SWAP3),
- byte(Instruction::POP), // first ++
+ uint8_t(Instruction::SWAP3),
+ uint8_t(Instruction::POP), // first ++
// Stack here: (a+1) x a
- byte(Instruction::DUP3),
- byte(Instruction::PUSH1), 0x1,
- byte(Instruction::ADD),
+ uint8_t(Instruction::DUP3),
+ uint8_t(Instruction::PUSH1), 0x1,
+ uint8_t(Instruction::ADD),
// Stack here: (a+1) x a (a+2)
- byte(Instruction::SWAP3),
- byte(Instruction::POP),
+ uint8_t(Instruction::SWAP3),
+ uint8_t(Instruction::POP),
// Stack here: (a+2) x a
- byte(Instruction::DUP3), // second ++
- byte(Instruction::XOR),
+ uint8_t(Instruction::DUP3), // second ++
+ uint8_t(Instruction::XOR),
// Stack here: (a+2) x a^(a+2)
- byte(Instruction::DUP3),
- byte(Instruction::DUP1),
- byte(Instruction::PUSH1), 0x1,
- byte(Instruction::SWAP1),
- byte(Instruction::SUB),
+ uint8_t(Instruction::DUP3),
+ uint8_t(Instruction::DUP1),
+ uint8_t(Instruction::PUSH1), 0x1,
+ uint8_t(Instruction::SWAP1),
+ uint8_t(Instruction::SUB),
// Stack here: (a+2) x a^(a+2) (a+2) (a+1)
- byte(Instruction::SWAP4),
- byte(Instruction::POP), // first --
- byte(Instruction::XOR),
+ uint8_t(Instruction::SWAP4),
+ uint8_t(Instruction::POP), // first --
+ uint8_t(Instruction::XOR),
// Stack here: (a+1) x a^(a+2)^(a+2)
- byte(Instruction::DUP3),
- byte(Instruction::PUSH1), 0x1,
- byte(Instruction::SWAP1),
- byte(Instruction::SUB),
+ uint8_t(Instruction::DUP3),
+ uint8_t(Instruction::PUSH1), 0x1,
+ uint8_t(Instruction::SWAP1),
+ uint8_t(Instruction::SUB),
// Stack here: (a+1) x a^(a+2)^(a+2) a
- byte(Instruction::SWAP3),
- byte(Instruction::POP), // second ++
+ uint8_t(Instruction::SWAP3),
+ uint8_t(Instruction::POP), // second ++
// Stack here: a x a^(a+2)^(a+2)
- byte(Instruction::DUP3), // will change
- byte(Instruction::XOR),
- byte(Instruction::SWAP1),
- byte(Instruction::POP),
- byte(Instruction::DUP1)});
+ uint8_t(Instruction::DUP3), // will change
+ uint8_t(Instruction::XOR),
+ uint8_t(Instruction::SWAP1),
+ uint8_t(Instruction::POP),
+ uint8_t(Instruction::DUP1)});
// Stack here: a x a^(a+2)^(a+2)^a
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -445,16 +445,16 @@ BOOST_AUTO_TEST_CASE(assignment)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b
- bytes expectation({byte(Instruction::PUSH1), 0x2,
- byte(Instruction::DUP2),
- byte(Instruction::DUP4),
- byte(Instruction::ADD),
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x2,
+ uint8_t(Instruction::DUP2),
+ uint8_t(Instruction::DUP4),
+ uint8_t(Instruction::ADD),
// Stack here: a b 2 a+b
- byte(Instruction::SWAP3),
- byte(Instruction::POP),
- byte(Instruction::DUP3),
+ uint8_t(Instruction::SWAP3),
+ uint8_t(Instruction::POP),
+ uint8_t(Instruction::DUP3),
// Stack here: a+b b 2 a+b
- byte(Instruction::MUL)});
+ uint8_t(Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -467,7 +467,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80));
+ bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -480,7 +480,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
+ bytes expectation(bytes({uint8_t(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -495,7 +495,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals)
)";
bytes code = compileFirstExpression(sourceCode);
- bytes expectation(bytes({byte(Instruction::PUSH1), 0xbf}));
+ bytes expectation(bytes({uint8_t(Instruction::PUSH1), 0xbf}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -514,8 +514,8 @@ BOOST_AUTO_TEST_CASE(blockhash)
bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
- bytes expectation({byte(Instruction::PUSH1), 0x03,
- byte(Instruction::BLOCKHASH)});
+ bytes expectation({uint8_t(Instruction::PUSH1), 0x03,
+ uint8_t(Instruction::BLOCKHASH)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -533,7 +533,7 @@ BOOST_AUTO_TEST_CASE(gas_left)
{make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
);
- bytes expectation = bytes({byte(Instruction::GAS)});
+ bytes expectation = bytes({uint8_t(Instruction::GAS)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp
index e171d974..ee637261 100644
--- a/test/libsolidity/SolidityTypes.cpp
+++ b/test/libsolidity/SolidityTypes.cpp
@@ -157,9 +157,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
BOOST_CHECK_EQUAL(RationalNumberType(rational(7, 1)).identifier(), "t_rational_7_by_1");
BOOST_CHECK_EQUAL(RationalNumberType(rational(200, 77)).identifier(), "t_rational_200_by_77");
BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77");
- BOOST_CHECK_EQUAL(RationalNumberType(rational(-2 * 200, -2 * 77)).identifier(), "t_rational_200_by_77");
BOOST_CHECK_EQUAL(RationalNumberType(rational(-2 * 200, 2 * 77)).identifier(), "t_rational_minus_200_by_77");
- BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, -2 * 77)).identifier(), "t_rational_minus_200_by_77");
BOOST_CHECK_EQUAL(
StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
diff --git a/test/libsolidity/syntaxTests/array/length/parameter_too_large.sol b/test/libsolidity/syntaxTests/array/length/parameter_too_large.sol
new file mode 100644
index 00000000..02e0a7cc
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/length/parameter_too_large.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(bytes32[1263941234127518272] memory) public pure {}
+}
+// ----
+// TypeError: (26-61): Array is too large to be encoded.
diff --git a/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim.sol b/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim.sol
new file mode 100644
index 00000000..5f96ecd5
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim.sol
@@ -0,0 +1,11 @@
+contract C {
+ function f(bytes32[1263941234127518272][500] memory) public pure {}
+ function f(uint[2**30][] memory) public pure {}
+ function f(uint[2**30][2**30][] memory) public pure {}
+ function f(uint[2**16][2**16][] memory) public pure {}
+}
+// ----
+// TypeError: (26-66): Array is too large to be encoded.
+// TypeError: (96-116): Array is too large to be encoded.
+// TypeError: (146-173): Array is too large to be encoded.
+// TypeError: (203-230): Array is too large to be encoded.
diff --git a/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim_ABIv2.sol b/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim_ABIv2.sol
new file mode 100644
index 00000000..de1fde3f
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/length/parameter_too_large_multidim_ABIv2.sol
@@ -0,0 +1,10 @@
+pragma experimental ABIEncoderV2;
+
+contract C {
+ function f(bytes32[1263941234127518272][500] memory) public pure {}
+ function f(uint[2**30][2**30][][] memory) public pure {}
+}
+// ----
+// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
+// TypeError: (61-101): Array is too large to be encoded.
+// TypeError: (131-160): Array is too large to be encoded.
diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp
index 44c6411a..4ed52b47 100644
--- a/test/libyul/Inliner.cpp
+++ b/test/libyul/Inliner.cpp
@@ -49,10 +49,10 @@ string inlinableFunctions(string const& _source)
InlinableExpressionFunctionFinder funFinder;
funFinder(ast);
- return boost::algorithm::join(
- funFinder.inlinableFunctions() | boost::adaptors::map_keys,
- ","
- );
+ vector<string> functionNames;
+ for (auto const& f: funFinder.inlinableFunctions())
+ functionNames.emplace_back(f.first.str());
+ return boost::algorithm::join(functionNames, ",");
}
}
diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp
index 0378764d..d455c892 100644
--- a/test/libyul/YulOptimizerTest.cpp
+++ b/test/libyul/YulOptimizerTest.cpp
@@ -22,6 +22,7 @@
#include <test/Options.h>
#include <libyul/optimiser/BlockFlattener.h>
+#include <libyul/optimiser/VarDeclPropagator.h>
#include <libyul/optimiser/Disambiguator.h>
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
#include <libyul/optimiser/NameCollector.h>
@@ -102,6 +103,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
disambiguate();
BlockFlattener{}(*m_ast);
}
+ else if (m_optimizerStep == "varDeclPropagator")
+ {
+ disambiguate();
+ VarDeclPropagator{}(*m_ast);
+ }
else if (m_optimizerStep == "commonSubexpressionEliminator")
{
disambiguate();
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul
new file mode 100644
index 00000000..54fea2fb
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/init_assignment_inside_if.yul
@@ -0,0 +1,17 @@
+{
+ let a := 4
+ let x
+ if a {
+ x := 2
+ }
+}
+// ----
+// varDeclPropagator
+// {
+// let a := 4
+// let x
+// if a
+// {
+// x := 2
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul
new file mode 100644
index 00000000..4ac07031
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/multi_assignment_vardecl.yul
@@ -0,0 +1,13 @@
+{
+ function f() -> a, b, c {}
+ let x, y, z
+ z, x, y := f()
+}
+// ----
+// varDeclPropagator
+// {
+// function f() -> a, b, c
+// {
+// }
+// let z, x, y := f()
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul
new file mode 100644
index 00000000..ca921500
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/overwrite.yul
@@ -0,0 +1,11 @@
+{
+ let a
+ a := 4
+ a := 5
+}
+// ----
+// varDeclPropagator
+// {
+// let a := 4
+// a := 5
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul
new file mode 100644
index 00000000..3affcac6
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/rewrite_removes_unused_var.yul
@@ -0,0 +1,10 @@
+{
+ let a, b
+ a := mload(0)
+}
+// ----
+// varDeclPropagator
+// {
+// let b
+// let a := mload(0)
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul
new file mode 100644
index 00000000..117e0cc9
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/simple1.yul
@@ -0,0 +1,9 @@
+{
+ let f
+ f := mload(0)
+}
+// ----
+// varDeclPropagator
+// {
+// let f := mload(0)
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul
new file mode 100644
index 00000000..e8c91e10
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/split_assign_splits_vardecl.yul
@@ -0,0 +1,11 @@
+{
+ let a, b
+ a := mload(0)
+ b := mload(1)
+}
+// ----
+// varDeclPropagator
+// {
+// let a := mload(0)
+// let b := mload(1)
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul
new file mode 100644
index 00000000..5312112a
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/use_before_init.yul
@@ -0,0 +1,12 @@
+{
+ let b
+ let a := b
+ b := 1
+}
+// ----
+// varDeclPropagator
+// {
+// let b
+// let a := b
+// b := 1
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul b/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul
new file mode 100644
index 00000000..e27785dd
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclPropagator/use_doesnt_rewrite.yul
@@ -0,0 +1,16 @@
+{
+ function f(x) {}
+ let a
+ f(a)
+ a := 4
+}
+// ----
+// varDeclPropagator
+// {
+// function f(x)
+// {
+// }
+// let a
+// f(a)
+// a := 4
+// }