Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Language Features:

Compiler Features:
* Commandline Interface: Introduce `--experimental` flag required for enabling the experimental mode.
* General: Introduce the SSA CFG codegen (experimental).
* General: Restrict the existing experimental features (`generic-solidity`, `lsp`, `ethdebug`, `eof`, `evm`, `ast-import`, `evmasm-import`, `ir-ast`, `ssa-cfg`) to experimental mode.
* Metadata: Store the state of the experimental mode in JSON and CBOR metadata. In CBOR this broadens the meaning of the existing `experimental` field, which used to indicate only the presence of certain experimental pragmas in the source.
* Standard JSON Interface: Introduce `settings.experimental` setting required for enabling the experimental mode.
Expand Down
7 changes: 6 additions & 1 deletion docs/using-the-compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ Input Description
// Optional: Change compilation pipeline to go through the Yul intermediate representation.
// This is false by default.
"viaIR": true,
// Optional: Turn on SSA CFG-based code generation via the IR (experimental).
// Implies viaIR: true. This is false by default.
"viaSSACFG": false,
// Optional: Debugging settings
"debug": {
// How to treat revert (and require) reason strings. Settings are
Expand Down Expand Up @@ -766,5 +769,7 @@ The table below details all currently available experimental features.
+-----------------------+--------------------------+------------------+-------------------------------------------------------------------+
| Ethdebug | ``ethdebug`` | no | ``--ethdebug``, ``--ethdebug-runtime``, ``--debug-info ethdebug`` |
+-----------------------+--------------------------+------------------+-------------------------------------------------------------------+
| Yul SSA CFG exporter | ``ssa-cfg`` | no | ``--yul-cfg-json`` |
| | | no | ``--yul-cfg-json`` |
| SSA CFG + ``ssa-cfg`` +------------------+-------------------------------------------------------------------+
| | | yes | ``--via-ssa-cfg`` |
+-----------------------+--------------------------+------------------+-------------------------------------------------------------------+
2 changes: 2 additions & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,8 @@ std::string CompilerStack::createMetadata(Contract const& _contract, bool _forIR
meta["settings"]["experimental"] = m_experimental;
if (m_eofVersion.has_value())
meta["settings"]["eofVersion"] = *m_eofVersion;
if (m_viaSSACFG)
meta["settings"]["viaSSACFG"] = m_viaSSACFG;
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
*_contract.contract->annotation().canonicalName;

Expand Down
28 changes: 26 additions & 2 deletions libsolidity/interface/StandardCompiler.cpp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

viaSSACFG: true should be disallowed in EVMAssembly mode (which goes through importEVMAssembly() and just ignores the setting).

I see that we're not disallowing viaIR there either. That perhaps should be fixed in a separate PR covering all the stray options we're allowing there but shouldn't.

Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ std::optional<Json> checkAuxiliaryInputKeys(Json const& _input)

std::optional<Json> checkSettingsKeys(Json const& _input)
{
static std::set<std::string> keys{"debug", "evmVersion", "experimental", "eofVersion", "libraries", "metadata", "modelChecker", "optimizer", "outputSelection", "remappings", "stopAfter", "viaIR"};
static std::set<std::string> keys{"debug", "evmVersion", "experimental", "eofVersion", "libraries", "metadata", "modelChecker", "optimizer", "outputSelection", "remappings", "stopAfter", "viaIR", "viaSSACFG"};
return checkKeys(_input, keys, "settings");
}

Expand Down Expand Up @@ -848,6 +848,22 @@ std::variant<StandardCompiler::InputsAndSettings, Json> StandardCompiler::parseI
ret.viaIR = settings["viaIR"].get<bool>();
}

if (settings.contains("viaSSACFG"))
{
if (!settings["viaSSACFG"].is_boolean())
return formatFatalError(Error::Type::JSONError, "\"settings.viaSSACFG\" must be a Boolean.");
ret.viaSSACFG = settings["viaSSACFG"].get<bool>();
if (ret.viaSSACFG)
{
if (settings.contains("viaIR") && !ret.viaIR)
return formatFatalError(
Error::Type::JSONError,
"\"settings.viaSSACFG\" requires compilation via IR."
);
ret.viaIR = true;
}
}

if (settings.contains("evmVersion"))
{
if (!settings["evmVersion"].is_string())
Expand Down Expand Up @@ -1239,8 +1255,12 @@ std::variant<StandardCompiler::InputsAndSettings, Json> StandardCompiler::parseI
}

if (isEthdebugRequested(ret.outputSelection))
{
if (ret.optimiserSettings.runYulOptimiser)
solUnimplemented("Optimization is not yet supported with ethdebug.");
if (ret.viaSSACFG)
solUnimplemented("SSA CFG codegen does not yet support ethdebug.");
}

if (!ret.experimental)
{
Expand All @@ -1256,6 +1276,9 @@ std::variant<StandardCompiler::InputsAndSettings, Json> StandardCompiler::parseI

if (ret.eofVersion.has_value())
return formatFatalError(Error::Type::FatalError, "'eofVersion' setting is experimental and can only be used with the 'settings.experimental' option enabled.");

if (ret.viaSSACFG)
return formatFatalError(Error::Type::FatalError, "'viaSSACFG' setting is experimental and can only be used with the 'settings.experimental' option enabled.");
}

return {std::move(ret)};
Expand Down Expand Up @@ -1406,6 +1429,7 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
for (auto const& smtLib2Response: _inputsAndSettings.smtLib2Responses)
compilerStack.addSMTLib2Response(smtLib2Response.first, smtLib2Response.second);
compilerStack.setViaIR(_inputsAndSettings.viaIR);
compilerStack.setViaSSACFG(_inputsAndSettings.viaSSACFG);
compilerStack.setEVMVersion(_inputsAndSettings.evmVersion);
compilerStack.setEOFVersion(_inputsAndSettings.eofVersion);
compilerStack.setRemappings(std::move(_inputsAndSettings.remappings));
Expand Down Expand Up @@ -1763,7 +1787,7 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
output["sources"][sourceName] = sourceResult;
}
stack.optimize();
std::tie(object, deployedObject) = stack.assembleWithDeployed();
std::tie(object, deployedObject) = stack.assembleWithDeployed({}, _inputsAndSettings.viaSSACFG);
if (object.bytecode)
object.bytecode->link(_inputsAndSettings.libraries);
if (deployedObject.bytecode)
Expand Down
1 change: 1 addition & 0 deletions libsolidity/interface/StandardCompiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class StandardCompiler
Json outputSelection;
ModelCheckerSettings modelCheckerSettings = ModelCheckerSettings{};
bool viaIR = false;
bool viaSSACFG = false;
bool experimental = false;
};

Expand Down
3 changes: 2 additions & 1 deletion solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ void CommandLineInterface::compile()
m_compiler->setRemappings(m_options.input.remappings);
m_compiler->setLibraries(m_options.linker.libraries);
m_compiler->setViaIR(m_options.output.viaIR);
m_compiler->setViaSSACFG(m_options.output.viaSSACFG);
m_compiler->setEVMVersion(m_options.output.evmVersion);
m_compiler->setEOFVersion(m_options.output.eofVersion);
m_compiler->setRevertStringBehaviour(m_options.output.revertStrings);
Expand Down Expand Up @@ -1322,7 +1323,7 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y

stack.optimize();

yul::MachineAssemblyObject object = stack.assemble(_targetMachine);
yul::MachineAssemblyObject object = stack.assemble(_targetMachine, m_options.output.viaSSACFG);
if (object.bytecode)
object.bytecode->link(m_options.linker.libraries);
objects.insert({sourceUnitName, std::move(object)});
Expand Down
26 changes: 24 additions & 2 deletions solc/CommandLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static std::string const g_strEVM = "evm";
static std::string const g_strEVMVersion = "evm-version";
static std::string const g_strEOFVersion = "experimental-eof-version";
static std::string const g_strViaIR = "via-ir";
static std::string const g_strViaSSACFG = "via-ssa-cfg";
static std::string const g_strExperimentalViaIR = "experimental-via-ir";
static std::string const g_strExperimental = "experimental";
static std::string const g_strGas = "gas";
Expand Down Expand Up @@ -623,7 +624,11 @@ General Information)").c_str(),
)
(
g_strViaIR.c_str(),
"Turn on compilation mode via the IR."
"Turn on compilation via IR."
)
(
g_strViaSSACFG.c_str(),
"(experimental) Turn on SSA CFG-based code generation. Implies compilation via IR."
)
(
g_strRevertStrings.c_str(),
Expand Down Expand Up @@ -999,6 +1004,7 @@ void CommandLineParser::processArgs()
"ethdebug",
"ethdebug-runtime",
g_strEOFVersion,
g_strViaSSACFG,
});

if (m_args.count(g_strHelp) > 0)
Expand Down Expand Up @@ -1063,7 +1069,8 @@ void CommandLineParser::processArgs()
{g_strModelCheckerTimeout, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerBMCLoopIterations, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerContracts, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerTargets, {InputMode::Compiler, InputMode::CompilerWithASTImport}}
{g_strModelCheckerTargets, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strViaSSACFG, {InputMode::Compiler, InputMode::CompilerWithASTImport, InputMode::Assembler}}
};
std::vector<std::string> invalidOptionsForCurrentInputMode;
for (auto const& [optionName, inputModes]: validOptionInputModeCombinations)
Expand Down Expand Up @@ -1372,8 +1379,17 @@ void CommandLineParser::processArgs()
"Optimizer can only be used for strict assembly. Use --" + g_strStrictAssembly + "."
);

m_options.output.viaSSACFG = m_args.contains(g_strViaSSACFG);
if (m_options.output.viaSSACFG)
if (m_options.assembly.inputLanguage != Input::StrictAssembly)
solThrow(
CommandLineValidationError,
"--" + g_strViaSSACFG + " can only be used with strict assembly. Use --" + g_strStrictAssembly + "."
);
if (m_options.compiler.outputs.ethdebug || m_options.compiler.outputs.ethdebugRuntime)
{
if (m_options.output.viaSSACFG)
solUnimplemented("ethdebug is not yet supported with --" + g_strViaSSACFG + ".");
if (m_options.optimiserSettings().runYulOptimiser)
solUnimplemented(
"Optimization (using --" + g_strOptimize + ") is not yet supported with ethdebug."
Expand Down Expand Up @@ -1514,6 +1530,9 @@ void CommandLineParser::processArgs()
m_args.count(g_strModelCheckerTargets) ||
m_args.count(g_strModelCheckerTimeout);
m_options.output.viaIR = (m_args.count(g_strExperimentalViaIR) > 0 || m_args.count(g_strViaIR) > 0);
m_options.output.viaSSACFG = m_args.contains(g_strViaSSACFG);
if (m_options.output.viaSSACFG)
m_options.output.viaIR = true;

solAssert(
m_options.input.mode == InputMode::Compiler ||
Expand All @@ -1540,6 +1559,9 @@ void CommandLineParser::processArgs()
enableEthdebugMessage + " output can only be selected, if --via-ir was specified."
);

if (m_options.output.viaSSACFG)
solUnimplemented("ethdebug is not yet supported with --" + g_strViaSSACFG + ".");

if (incompatibleEthdebugOutputs)
solThrow(
CommandLineValidationError,
Expand Down
1 change: 1 addition & 0 deletions solc/CommandLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ struct CommandLineOptions
bool overwriteFiles = false;
langutil::EVMVersion evmVersion;
bool viaIR = false;
bool viaSSACFG = false;
RevertStrings revertStrings = RevertStrings::Default;
std::optional<langutil::DebugInfoSelection> debugInfoSelection;
CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful;
Expand Down
1 change: 1 addition & 0 deletions test/cmdlineTests/metadata_via_ssa_cfg/args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--metadata --experimental --via-ssa-cfg
4 changes: 4 additions & 0 deletions test/cmdlineTests/metadata_via_ssa_cfg/input.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity *;

contract C {}
4 changes: 4 additions & 0 deletions test/cmdlineTests/metadata_via_ssa_cfg/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

======= input.sol:C =======
Metadata:
{"compiler":{"version": "<VERSION REMOVED>"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"input.sol":"C"},"evmVersion":"osaka","experimental":true,"libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[],"viaIR":true,"viaSSACFG":true},"sources":{"input.sol":{"keccak256":"0x5cf617b1707a484e3c4bd59643013dec76ab7d75900b46855214729ae3e0ceb0","license":"GPL-3.0","urls":["bzz-raw://ac418a02dfadf87234150d3568f33269e3f49460345cb39300e017a6d755eff2","dweb:/ipfs/QmQq3owBu25x2WV46HB1WyKzJpxiAPecU7eMKqtXCF7eeS"]}},"version":1}
15 changes: 15 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_ethdebug/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"language": "Solidity",
"sources": {
"A.sol": {
"content": "contract A {}"
}
},
"settings": {
"experimental": true,
"viaSSACFG": true,
"outputSelection": {
"*": {"*": ["evm.bytecode.ethdebug"]}
}
}
}
11 changes: 11 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_ethdebug/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"errors": [
{
"component": "general",
"formattedMessage": "SSA CFG codegen does not yet support ethdebug.",
"message": "SSA CFG codegen does not yet support ethdebug.",
"severity": "error",
"type": "UnimplementedFeatureError"
}
]
}
11 changes: 11 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_no_experimental/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"language": "Solidity",
"sources": {
"A.sol": {
"content": "contract A { constructor() { uint x = 2; { uint y = 3; } } }"
}
},
"settings": {
"viaSSACFG": true
}
}
11 changes: 11 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_no_experimental/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"errors": [
{
"component": "general",
"formattedMessage": "'viaSSACFG' setting is experimental and can only be used with the 'settings.experimental' option enabled.",
"message": "'viaSSACFG' setting is experimental and can only be used with the 'settings.experimental' option enabled.",
"severity": "error",
"type": "FatalError"
}
]
}
13 changes: 13 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_via_ir_false/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"language": "Solidity",
"sources": {
"A.sol": {
"content": "contract A {}"
}
},
"settings": {
"experimental": true,
"viaIR": false,
"viaSSACFG": true
}
}
11 changes: 11 additions & 0 deletions test/cmdlineTests/standard_via_ssa_cfg_via_ir_false/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"errors": [
{
"component": "general",
"formattedMessage": "\"settings.viaSSACFG\" requires compilation via IR.",
"message": "\"settings.viaSSACFG\" requires compilation via IR.",
"severity": "error",
"type": "JSONError"
}
]
}
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_ethdebug/args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--experimental --via-ssa-cfg --ethdebug
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_ethdebug/err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: ethdebug is not yet supported with --via-ssa-cfg.
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_ethdebug/exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
4 changes: 4 additions & 0 deletions test/cmdlineTests/via_ssa_cfg_ethdebug/input.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;

contract C {}
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_without_experimental/args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--via-ssa-cfg
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_without_experimental/err
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: The following options are only available in experimental mode: --via-ssa-cfg. To enable experimental mode, use the --experimental flag.
1 change: 1 addition & 0 deletions test/cmdlineTests/via_ssa_cfg_without_experimental/exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
6 changes: 6 additions & 0 deletions test/cmdlineTests/via_ssa_cfg_without_experimental/input.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;

contract C {
function f() public {}
}
45 changes: 45 additions & 0 deletions test/libsolidity/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,51 @@ BOOST_AUTO_TEST_CASE(metadata_viair)
check(sourceCode, false);
}

BOOST_AUTO_TEST_CASE(metadata_viassacfg)
{
static auto constexpr sourceCode = R"(
pragma solidity >=0.0;
contract test {
}
)";

auto check = [](char const* _src, bool _viaSSACFG)
{
CompilerStack compilerStack;
compilerStack.setSources({{"", _src}});
compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
compilerStack.setOptimiserSettings(solidity::test::CommonOptions::get().optimize);
compilerStack.setViaIR(true);
compilerStack.setExperimental(true);
compilerStack.setViaSSACFG(_viaSSACFG);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");

Json metadata;
BOOST_REQUIRE(util::jsonParseStrict(compilerStack.metadata("test"), metadata));
BOOST_CHECK(solidity::test::isValidMetadata(metadata));
BOOST_CHECK(metadata.contains("settings"));
BOOST_CHECK(metadata["settings"].contains("viaIR"));
BOOST_CHECK(metadata["settings"]["viaIR"].get<bool>());
if (_viaSSACFG)
{
BOOST_CHECK(metadata["settings"].contains("viaSSACFG"));
BOOST_CHECK(metadata["settings"]["viaSSACFG"].get<bool>());
}
else
BOOST_CHECK(!metadata["settings"].contains("viaSSACFG"));

std::map<std::string, std::string> const parsedCBORMetadata = requireParsedCBORMetadata(
compilerStack.runtimeObject("test").bytecode,
CompilerStack::MetadataFormat::WithReleaseVersionTag
);

BOOST_CHECK(parsedCBORMetadata.contains("experimental"));
};

check(sourceCode, true);
check(sourceCode, false);
}

BOOST_AUTO_TEST_CASE(metadata_revert_strings)
{
CompilerStack compilerStack;
Expand Down
Loading