Skip to content

Commit 27f4e90

Browse files
committed
EVMDialect: add test that enforces builtin handle compatibility
Between current default dialect as well as latest dialect and all other dialects.
1 parent 40c9c7a commit 27f4e90

File tree

5 files changed

+170
-0
lines changed

5 files changed

+170
-0
lines changed

Diff for: libyul/backends/evm/EVMDialect.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include <range/v3/algorithm/all_of.hpp>
3434
#include <range/v3/view/enumerate.hpp>
35+
#include <range/v3/view/map.hpp>
3536

3637
#include <regex>
3738
#include <utility>
@@ -616,6 +617,11 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio
616617
};
617618
}
618619

620+
std::set<std::string_view> EVMDialect::builtinFunctionNames() const
621+
{
622+
return ranges::views::keys(m_builtinFunctionsByName) | ranges::to<std::set>;
623+
}
624+
619625
BuiltinFunctionForEVM EVMDialect::createVerbatimFunctionFromHandle(BuiltinHandle const& _handle)
620626
{
621627
return std::apply(createVerbatimFunction, verbatimIndexToArgsAndRets(_handle.id));

Diff for: libyul/backends/evm/EVMDialect.h

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class EVMDialect: public Dialect
113113
static size_t constexpr verbatimMaxInputSlots = 100;
114114
static size_t constexpr verbatimMaxOutputSlots = 100;
115115

116+
std::set<std::string_view> builtinFunctionNames() const;
117+
116118
protected:
117119
static bool constexpr isVerbatimHandle(BuiltinHandle const& _handle) { return _handle.id < verbatimIDOffset; }
118120
static BuiltinFunctionForEVM createVerbatimFunctionFromHandle(BuiltinHandle const& _handle);

Diff for: test/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ set(libyul_sources
145145
libyul/ControlFlowSideEffectsTest.h
146146
libyul/EVMCodeTransformTest.cpp
147147
libyul/EVMCodeTransformTest.h
148+
libyul/EVMDialectCompatibility.h
149+
libyul/EVMDialectCompatibility.cpp
148150
libyul/FunctionSideEffects.cpp
149151
libyul/FunctionSideEffects.h
150152
libyul/Inliner.cpp

Diff for: test/libyul/EVMDialectCompatibility.cpp

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
#include <test/libyul/EVMDialectCompatibility.h>
20+
21+
#include <boost/test/data/test_case.hpp>
22+
#include <boost/test/data/monomorphic.hpp>
23+
24+
namespace bdata = boost::unit_test::data;
25+
26+
using namespace solidity;
27+
using namespace solidity::yul;
28+
using namespace solidity::yul::test;
29+
30+
BOOST_AUTO_TEST_SUITE(EVMDialectCompatibility)
31+
32+
BOOST_DATA_TEST_CASE(
33+
builtin_function_handle_compatibility_non_eof,
34+
bdata::make(generateEVMDialectConfigurationsToTest(std::nullopt)),
35+
evmDialectConfigurationToTest
36+
)
37+
{
38+
auto const& dialectToTestAgainst = evmDialectConfigurationToTest.dialect();
39+
// no object access for current
40+
{
41+
auto const& currentDialect = EVMDialect::strictAssemblyForEVM({}, std::nullopt);
42+
for (auto const& builtinFunctionName: currentDialect.builtinFunctionNames())
43+
requireBuiltinCompatibility(currentDialect, dialectToTestAgainst, builtinFunctionName);
44+
}
45+
// object access for current
46+
{
47+
auto const& currentDialect = EVMDialect::strictAssemblyForEVMObjects({}, std::nullopt);
48+
for (auto const& builtinFunctionName: currentDialect.builtinFunctionNames())
49+
requireBuiltinCompatibility(currentDialect, dialectToTestAgainst, builtinFunctionName);
50+
}
51+
}
52+
53+
BOOST_DATA_TEST_CASE(
54+
builtin_function_handle_compatibility_eof,
55+
bdata::monomorphic::grid(
56+
bdata::make(generateEVMDialectConfigurationsToTest(std::nullopt)) + bdata::make(generateEVMDialectConfigurationsToTest(1)),
57+
bdata::make({false, true})
58+
),
59+
evmDialectConfigurationToTest,
60+
withEOF
61+
)
62+
{
63+
auto const& dialectToTestAgainst = evmDialectConfigurationToTest.dialect();
64+
langutil::EVMVersion latestEVMVersion = langutil::EVMVersion::allVersions().back();
65+
std::optional<uint8_t> eofVersion = std::nullopt;
66+
if (withEOF)
67+
eofVersion = 1;
68+
// no object access for latest
69+
{
70+
auto const& latestDialect = EVMDialect::strictAssemblyForEVM(latestEVMVersion, eofVersion);
71+
for (auto const& builtinFunctionName: latestDialect.builtinFunctionNames())
72+
requireBuiltinCompatibility(latestDialect, dialectToTestAgainst, builtinFunctionName);
73+
}
74+
// object access for latest
75+
{
76+
auto const& latestDialect = EVMDialect::strictAssemblyForEVMObjects(latestEVMVersion, eofVersion);
77+
for (auto const& builtinFunctionName: latestDialect.builtinFunctionNames())
78+
requireBuiltinCompatibility(latestDialect, dialectToTestAgainst, builtinFunctionName);
79+
}
80+
}
81+
82+
BOOST_AUTO_TEST_SUITE_END()

Diff for: test/libyul/EVMDialectCompatibility.h

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
// SPDX-License-Identifier: GPL-3.0
18+
19+
#pragma once
20+
21+
#include <libyul/backends/evm/EVMDialect.h>
22+
23+
#include <boost/test/unit_test.hpp>
24+
25+
#include <fmt/format.h>
26+
27+
#include <cstdint>
28+
#include <optional>
29+
#include <vector>
30+
31+
32+
namespace solidity::yul::test
33+
{
34+
35+
inline void requireBuiltinCompatibility(EVMDialect const& _dialect1, EVMDialect const& _dialect2, std::string_view const _builtin)
36+
{
37+
if (auto const currentHandle = _dialect1.findBuiltin(_builtin))
38+
if (auto const handle = _dialect2.findBuiltin(_builtin))
39+
BOOST_REQUIRE_MESSAGE(
40+
*handle == *currentHandle,
41+
fmt::format("Failed for \"{}\" with IDs {} =/= {}.", _builtin, currentHandle->id, handle->id)
42+
);
43+
}
44+
45+
struct EVMDialectConfigurationToTest
46+
{
47+
EVMDialect const& dialect() const
48+
{
49+
return objectAccess ? EVMDialect::strictAssemblyForEVMObjects(evmVersion, eofVersion) : EVMDialect::strictAssemblyForEVM(evmVersion, eofVersion);
50+
}
51+
52+
friend std::ostream& operator<<(std::ostream& _out, EVMDialectConfigurationToTest const& _config)
53+
{
54+
_out << fmt::format(
55+
"EVMConfigurationToTest[{}, eof={}, objectAccess={}]",
56+
_config.evmVersion.name(),
57+
_config.eofVersion.has_value() ? std::to_string(*_config.eofVersion) : "null",
58+
_config.objectAccess
59+
);
60+
return _out;
61+
}
62+
63+
langutil::EVMVersion evmVersion;
64+
std::optional<uint8_t> eofVersion;
65+
bool objectAccess;
66+
};
67+
68+
inline std::vector<EVMDialectConfigurationToTest> generateEVMDialectConfigurationsToTest(std::optional<uint8_t> _eofVersion)
69+
{
70+
std::vector<EVMDialectConfigurationToTest> configs;
71+
for (bool providesObjectAccess: {false, true})
72+
for (auto evmVersion: langutil::EVMVersion::allVersions())
73+
if (!_eofVersion || evmVersion >= langutil::EVMVersion::firstWithEOF())
74+
configs.push_back(EVMDialectConfigurationToTest{evmVersion, _eofVersion, providesObjectAccess});
75+
return configs;
76+
}
77+
78+
}

0 commit comments

Comments
 (0)