Add viaIR option to CompilerStack

It also sets the experimental flag in the metadata to true.
This commit is contained in:
Alex Beregszaszi 2020-10-28 18:59:19 +00:00
parent c69c7f32ae
commit 301d7ea39e
3 changed files with 91 additions and 4 deletions

View File

@ -131,6 +131,13 @@ void CompilerStack::setRemappings(vector<Remapping> const& _remappings)
m_remappings = _remappings;
}
void CompilerStack::setViaIR(bool _viaIR)
{
if (m_stackState >= ParsedAndImported)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set viaIR before parsing."));
m_viaIR = _viaIR;
}
void CompilerStack::setEVMVersion(langutil::EVMVersion _version)
{
if (m_stackState >= ParsedAndImported)
@ -213,6 +220,7 @@ void CompilerStack::reset(bool _keepSettings)
{
m_remappings.clear();
m_libraries.clear();
m_viaIR = false;
m_evmVersion = langutil::EVMVersion();
m_modelCheckerSettings = ModelCheckerSettings{};
m_enabledSMTSolvers = smtutil::SMTSolverChoice::All();
@ -532,10 +540,15 @@ bool CompilerStack::compile(State _stopAfter)
{
try
{
if (m_generateEvmBytecode)
compileContract(*contract, otherCompilers);
if (m_generateIR || m_generateEwasm)
if (m_viaIR || m_generateIR || m_generateEwasm)
generateIR(*contract);
if (m_generateEvmBytecode)
{
if (m_viaIR)
generateEVMFromIR(*contract);
else
compileContract(*contract, otherCompilers);
}
if (m_generateEwasm)
generateEwasm(*contract);
}
@ -1250,6 +1263,36 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources);
}
void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
{
solAssert(m_stackState >= AnalysisPerformed, "");
if (m_hasError)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEVMFromIR with errors."));
if (!_contract.canBeDeployed())
return;
Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
solAssert(!compiledContract.yulIROptimized.empty(), "");
if (!compiledContract.object.bytecode.empty())
return;
// Re-parse the Yul IR in EVM dialect
yul::AssemblyStack stack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings);
stack.parseAndAnalyze("", compiledContract.yulIROptimized);
stack.optimize();
//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
// TODO: support passing metadata
auto result = stack.assemble(yul::AssemblyStack::Machine::EVM);
compiledContract.object = std::move(*result.bytecode);
// TODO: support runtimeObject
// TODO: add EIP-170 size check for runtimeObject
// TODO: refactor assemblyItems, runtimeAssemblyItems, generatedSources,
// assemblyString, assemblyJSON, and functionEntryPoints to work with this code path
}
void CompilerStack::generateEwasm(ContractDefinition const& _contract)
{
solAssert(m_stackState >= AnalysisPerformed, "");
@ -1395,6 +1438,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const
static vector<string> hashes{"ipfs", "bzzr1", "none"};
meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash));
if (m_viaIR)
meta["settings"]["viaIR"] = m_viaIR;
meta["settings"]["evmVersion"] = m_evmVersion.name();
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
*_contract.contract->annotation().canonicalName;
@ -1517,7 +1562,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract) const
else
solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash");
if (experimentalMode)
if (experimentalMode || m_viaIR)
encoder.pushBool("experimental", true);
if (m_release)
encoder.pushBytes("solc", VersionCompactBytes);

View File

@ -162,6 +162,10 @@ public:
m_parserErrorRecovery = _wantErrorRecovery;
}
/// Sets the pipeline to go through the Yul IR or not.
/// Must be set before parsing.
void setViaIR(bool _viaIR);
/// Set the EVM version used before running compile.
/// When called without an argument it will revert to the default version.
/// Must be set before parsing.
@ -399,7 +403,12 @@ private:
/// The IR is stored but otherwise unused.
void generateIR(ContractDefinition const& _contract);
/// Generate EVM representation for a single contract.
/// Depends on output generated by generateIR.
void generateEVMFromIR(ContractDefinition const& _contract);
/// Generate Ewasm representation for a single contract.
/// Depends on output generated by generateIR.
void generateEwasm(ContractDefinition const& _contract);
/// Links all the known library addresses in the available objects. Any unknown
@ -455,6 +464,7 @@ private:
OptimiserSettings m_optimiserSettings;
RevertStrings m_revertStrings = RevertStrings::Default;
State m_stopAfter = State::CompilationSuccessful;
bool m_viaIR = false;
langutil::EVMVersion m_evmVersion;
ModelCheckerSettings m_modelCheckerSettings;
smtutil::SMTSolverChoice m_enabledSMTSolvers;

View File

@ -282,6 +282,38 @@ BOOST_AUTO_TEST_CASE(metadata_useLiteralContent)
check(sourceCode, false);
}
BOOST_AUTO_TEST_CASE(metadata_viair)
{
char const* sourceCode = R"(
pragma solidity >=0.0;
contract test {
}
)";
auto check = [](char const* _src, bool _viair)
{
CompilerStack compilerStack;
compilerStack.setSources({{"", std::string(_src)}});
compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
compilerStack.setOptimiserSettings(solidity::test::CommonOptions::get().optimize);
compilerStack.setViaIR(_viair);
BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed");
string metadata_str = compilerStack.metadata("test");
Json::Value metadata;
util::jsonParseStrict(metadata_str, metadata);
BOOST_CHECK(solidity::test::isValidMetadata(metadata_str));
BOOST_CHECK(metadata.isMember("settings"));
if (_viair)
{
BOOST_CHECK(metadata["settings"].isMember("viaIR"));
BOOST_CHECK(metadata["settings"]["viaIR"].asBool());
}
};
check(sourceCode, true);
check(sourceCode, false);
}
BOOST_AUTO_TEST_CASE(metadata_revert_strings)
{
CompilerStack compilerStack;