mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
SemanticTest: Add a setting that explicitly states the minimal Yul optimization level that avoids "Stack too deep"
This commit is contained in:
parent
8e9496eb8b
commit
bc6d10f11d
@ -45,6 +45,17 @@ using namespace boost::algorithm;
|
|||||||
using namespace boost::unit_test;
|
using namespace boost::unit_test;
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
ostream& solidity::frontend::test::operator<<(ostream& _output, RequiresYulOptimizer _requiresYulOptimizer)
|
||||||
|
{
|
||||||
|
switch (_requiresYulOptimizer)
|
||||||
|
{
|
||||||
|
case RequiresYulOptimizer::False: _output << "false"; break;
|
||||||
|
case RequiresYulOptimizer::MinimalStack: _output << "minimalStack"; break;
|
||||||
|
case RequiresYulOptimizer::Full: _output << "full"; break;
|
||||||
|
}
|
||||||
|
return _output;
|
||||||
|
}
|
||||||
|
|
||||||
SemanticTest::SemanticTest(
|
SemanticTest::SemanticTest(
|
||||||
string const& _filename,
|
string const& _filename,
|
||||||
langutil::EVMVersion _evmVersion,
|
langutil::EVMVersion _evmVersion,
|
||||||
@ -66,6 +77,16 @@ SemanticTest::SemanticTest(
|
|||||||
static set<string> const yulRunTriggers{"also", "true"};
|
static set<string> const yulRunTriggers{"also", "true"};
|
||||||
static set<string> const legacyRunTriggers{"also", "false", "default"};
|
static set<string> const legacyRunTriggers{"also", "false", "default"};
|
||||||
|
|
||||||
|
m_requiresYulOptimizer = m_reader.enumSetting<RequiresYulOptimizer>(
|
||||||
|
"requiresYulOptimizer",
|
||||||
|
{
|
||||||
|
{toString(RequiresYulOptimizer::False), RequiresYulOptimizer::False},
|
||||||
|
{toString(RequiresYulOptimizer::MinimalStack), RequiresYulOptimizer::MinimalStack},
|
||||||
|
{toString(RequiresYulOptimizer::Full), RequiresYulOptimizer::Full},
|
||||||
|
},
|
||||||
|
toString(RequiresYulOptimizer::False)
|
||||||
|
);
|
||||||
|
|
||||||
m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false);
|
m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false);
|
||||||
if (m_runWithABIEncoderV1Only && !solidity::test::CommonOptions::get().useABIEncoderV1)
|
if (m_runWithABIEncoderV1Only && !solidity::test::CommonOptions::get().useABIEncoderV1)
|
||||||
m_shouldRun = false;
|
m_shouldRun = false;
|
||||||
@ -272,15 +293,38 @@ optional<AnnotatedEventSignature> SemanticTest::matchEvent(util::h256 const& has
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frontend::OptimiserSettings SemanticTest::optimizerSettingsFor(RequiresYulOptimizer _requiresYulOptimizer)
|
||||||
|
{
|
||||||
|
switch (_requiresYulOptimizer) {
|
||||||
|
case RequiresYulOptimizer::False:
|
||||||
|
return OptimiserSettings::minimal();
|
||||||
|
case RequiresYulOptimizer::MinimalStack:
|
||||||
|
{
|
||||||
|
OptimiserSettings settings = OptimiserSettings::minimal();
|
||||||
|
settings.runYulOptimiser = true;
|
||||||
|
settings.yulOptimiserSteps = "uljmul jmul";
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
case RequiresYulOptimizer::Full:
|
||||||
|
return OptimiserSettings::full();
|
||||||
|
}
|
||||||
|
unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||||
{
|
{
|
||||||
TestResult result = TestResult::Success;
|
TestResult result = TestResult::Success;
|
||||||
|
|
||||||
if (m_testCaseWantsLegacyRun && !m_eofVersion.has_value())
|
if (m_testCaseWantsLegacyRun && !m_eofVersion.has_value())
|
||||||
result = runTest(_stream, _linePrefix, _formatted, false);
|
result = runTest(_stream, _linePrefix, _formatted, false /* _isYulRun */);
|
||||||
|
|
||||||
if (m_testCaseWantsYulRun && result == TestResult::Success)
|
if (m_testCaseWantsYulRun && result == TestResult::Success)
|
||||||
result = runTest(_stream, _linePrefix, _formatted, true);
|
{
|
||||||
|
if (solidity::test::CommonOptions::get().optimize)
|
||||||
|
result = runTest(_stream, _linePrefix, _formatted, true /* _isYulRun */);
|
||||||
|
else
|
||||||
|
result = tryRunTestWithYulOptimizer(_stream, _linePrefix, _formatted);
|
||||||
|
}
|
||||||
|
|
||||||
if (result != TestResult::Success)
|
if (result != TestResult::Success)
|
||||||
solidity::test::CommonOptions::get().printSelectedOptions(
|
solidity::test::CommonOptions::get().printSelectedOptions(
|
||||||
@ -296,7 +340,8 @@ TestCase::TestResult SemanticTest::runTest(
|
|||||||
ostream& _stream,
|
ostream& _stream,
|
||||||
string const& _linePrefix,
|
string const& _linePrefix,
|
||||||
bool _formatted,
|
bool _formatted,
|
||||||
bool _isYulRun)
|
bool _isYulRun
|
||||||
|
)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
m_gasCostFailure = false;
|
m_gasCostFailure = false;
|
||||||
@ -470,6 +515,53 @@ TestCase::TestResult SemanticTest::runTest(
|
|||||||
return TestResult::Success;
|
return TestResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase::TestResult SemanticTest::tryRunTestWithYulOptimizer(
|
||||||
|
std::ostream& _stream,
|
||||||
|
std::string const& _linePrefix,
|
||||||
|
bool _formatted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
TestResult result{};
|
||||||
|
for (auto requiresYulOptimizer: {
|
||||||
|
RequiresYulOptimizer::False,
|
||||||
|
RequiresYulOptimizer::MinimalStack,
|
||||||
|
RequiresYulOptimizer::Full,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
ScopedSaveAndRestore optimizerSettings(
|
||||||
|
m_optimiserSettings,
|
||||||
|
optimizerSettingsFor(requiresYulOptimizer)
|
||||||
|
);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = runTest(_stream, _linePrefix, _formatted, true /* _isYulRun */);
|
||||||
|
}
|
||||||
|
catch (yul::StackTooDeepError const&)
|
||||||
|
{
|
||||||
|
if (requiresYulOptimizer == RequiresYulOptimizer::Full)
|
||||||
|
throw;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_requiresYulOptimizer != requiresYulOptimizer && result != TestResult::FatalError)
|
||||||
|
{
|
||||||
|
soltestAssert(result == TestResult::Success || result == TestResult::Failure);
|
||||||
|
|
||||||
|
AnsiColorized(_stream, _formatted, {BOLD, YELLOW})
|
||||||
|
<< _linePrefix << endl
|
||||||
|
<< _linePrefix << "requiresYulOptimizer is set to " << m_requiresYulOptimizer
|
||||||
|
<< " but should be " << requiresYulOptimizer << endl;
|
||||||
|
m_requiresYulOptimizer = requiresYulOptimizer;
|
||||||
|
return TestResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const
|
bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const
|
||||||
{
|
{
|
||||||
string setting =
|
string setting =
|
||||||
@ -581,6 +673,9 @@ void SemanticTest::printUpdatedSettings(ostream& _stream, string const& _linePre
|
|||||||
|
|
||||||
_stream << _linePrefix << "// ====" << endl;
|
_stream << _linePrefix << "// ====" << endl;
|
||||||
for (auto const& [settingName, settingValue]: settings)
|
for (auto const& [settingName, settingValue]: settings)
|
||||||
|
if (settingName == "requiresYulOptimizer")
|
||||||
|
_stream << _linePrefix << "// " << settingName << ": " << m_requiresYulOptimizer << endl;
|
||||||
|
else
|
||||||
_stream << _linePrefix << "// " << settingName << ": " << settingValue<< endl;
|
_stream << _linePrefix << "// " << settingName << ": " << settingValue<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,15 @@ struct AnnotatedEventSignature
|
|||||||
std::vector<std::string> nonIndexedTypes;
|
std::vector<std::string> nonIndexedTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class RequiresYulOptimizer
|
||||||
|
{
|
||||||
|
False,
|
||||||
|
MinimalStack,
|
||||||
|
Full,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& _output, RequiresYulOptimizer _requiresYulOptimizer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents a semantic test (or end-to-end test) and allows running it as part of the
|
* Class that represents a semantic test (or end-to-end test) and allows running it as part of the
|
||||||
* boost unit test environment or isoltest. It reads the Solidity source and an additional comment
|
* boost unit test environment or isoltest. It reads the Solidity source and an additional comment
|
||||||
@ -83,13 +92,26 @@ public:
|
|||||||
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {});
|
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TestResult runTest(std::ostream& _stream, std::string const& _linePrefix, bool _formatted, bool _isYulRun);
|
TestResult runTest(
|
||||||
|
std::ostream& _stream,
|
||||||
|
std::string const& _linePrefix,
|
||||||
|
bool _formatted,
|
||||||
|
bool _isYulRun
|
||||||
|
);
|
||||||
|
TestResult tryRunTestWithYulOptimizer(
|
||||||
|
std::ostream& _stream,
|
||||||
|
std::string const& _linePrefix,
|
||||||
|
bool _formatted
|
||||||
|
);
|
||||||
bool checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const;
|
bool checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const;
|
||||||
std::map<std::string, Builtin> makeBuiltins();
|
std::map<std::string, Builtin> makeBuiltins();
|
||||||
std::vector<SideEffectHook> makeSideEffectHooks() const;
|
std::vector<SideEffectHook> makeSideEffectHooks() const;
|
||||||
std::vector<std::string> eventSideEffectHook(FunctionCall const&) const;
|
std::vector<std::string> eventSideEffectHook(FunctionCall const&) const;
|
||||||
std::optional<AnnotatedEventSignature> matchEvent(util::h256 const& hash) const;
|
std::optional<AnnotatedEventSignature> matchEvent(util::h256 const& hash) const;
|
||||||
static std::string formatEventParameter(std::optional<AnnotatedEventSignature> _signature, bool _indexed, size_t _index, bytes const& _data);
|
static std::string formatEventParameter(std::optional<AnnotatedEventSignature> _signature, bool _indexed, size_t _index, bytes const& _data);
|
||||||
|
|
||||||
|
OptimiserSettings optimizerSettingsFor(RequiresYulOptimizer _requiresYulOptimizer);
|
||||||
|
|
||||||
SourceMap m_sources;
|
SourceMap m_sources;
|
||||||
std::size_t m_lineOffset;
|
std::size_t m_lineOffset;
|
||||||
std::vector<TestFunctionCall> m_tests;
|
std::vector<TestFunctionCall> m_tests;
|
||||||
@ -101,6 +123,7 @@ private:
|
|||||||
bool m_allowNonExistingFunctions = false;
|
bool m_allowNonExistingFunctions = false;
|
||||||
bool m_gasCostFailure = false;
|
bool m_gasCostFailure = false;
|
||||||
bool m_enforceGasCost = false;
|
bool m_enforceGasCost = false;
|
||||||
|
RequiresYulOptimizer m_requiresYulOptimizer{};
|
||||||
u256 m_enforceGasCostMinValue;
|
u256 m_enforceGasCostMinValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user