From 90c98a3289dc9dc7ef1e8fb131de139e39427e13 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 19 Dec 2019 16:01:28 +0100 Subject: [PATCH] Introduce typed EVM dialect. --- libyul/AssemblyStack.cpp | 2 +- libyul/backends/evm/EVMDialect.cpp | 64 +++++++++++++++++++++++++----- libyul/backends/evm/EVMDialect.h | 20 +++++++++- 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 35bcdf65c..87215179e 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -157,7 +157,7 @@ void AssemblyStack::compileEVM(AbstractAssembly& _assembly, bool _evm15, bool _o dialect = &EVMDialect::strictAssemblyForEVMObjects(m_evmVersion); break; case Language::Yul: - dialect = &EVMDialect::yulForEVM(m_evmVersion); + dialect = &EVMDialectTyped::instance(m_evmVersion); break; default: solAssert(false, "Invalid language."); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 6e2407ced..399445efa 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -203,15 +203,6 @@ EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _ return *dialects[_version]; } -EVMDialect const& EVMDialect::yulForEVM(langutil::EVMVersion _version) -{ - static map> dialects; - static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; - if (!dialects[_version]) - dialects[_version] = make_unique(_version, false); - return *dialects[_version]; -} - SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instruction) { return SideEffects{ @@ -222,3 +213,58 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio evmasm::SemanticInformation::invalidatesMemory(_instruction) }; } + +EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectAccess): + EVMDialect(_evmVersion, _objectAccess) +{ + defaultType = "u256"_yulstring; + m_functions["lt"_yulstring].returns = {"bool"_yulstring}; + m_functions["gt"_yulstring].returns = {"bool"_yulstring}; + m_functions["slt"_yulstring].returns = {"bool"_yulstring}; + m_functions["sgt"_yulstring].returns = {"bool"_yulstring}; + m_functions["eq"_yulstring].returns = {"bool"_yulstring}; + m_functions["iszero"_yulstring].returns = {"bool"_yulstring}; + m_functions["bitand"_yulstring] = m_functions["and"_yulstring]; + m_functions["bitor"_yulstring] = m_functions["or"_yulstring]; + m_functions["bitxor"_yulstring] = m_functions["xor"_yulstring]; + m_functions["and"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; + m_functions["and"_yulstring].returns = {"bool"_yulstring}; + m_functions["or"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; + m_functions["or"_yulstring].returns = {"bool"_yulstring}; + m_functions["xor"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; + m_functions["xor"_yulstring].returns = {"bool"_yulstring}; + m_functions["isfalse"_yulstring] = m_functions["iszero"_yulstring]; + m_functions["isfalse"_yulstring].parameters = {"bool"_yulstring}; + m_functions["popbool"_yulstring] = m_functions["pop"_yulstring]; + m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; + m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, false, []( + FunctionCall const&, + AbstractAssembly&, + BuiltinContext&, + std::function _visitArguments + ) { + _visitArguments(); + })); + m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; + m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, false, []( + FunctionCall const&, + AbstractAssembly& _assembly, + BuiltinContext&, + std::function _visitArguments + ) { + // TODO Should a value larger than 1 be invalid? + _visitArguments(); + _assembly.appendInstruction(evmasm::Instruction::ISZERO); + _assembly.appendInstruction(evmasm::Instruction::ISZERO); + })); + m_functions["u256_to_bool"_yulstring].returns = {"bool"_yulstring}; +} + +EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version) +{ + static map> dialects; + static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; + if (!dialects[_version]) + dialects[_version] = make_unique(_version, true); + return *dialects[_version]; +} diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index 0d7d8b6d9..a670b020f 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -74,7 +74,6 @@ struct EVMDialect: public Dialect static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version); static EVMDialect const& strictAssemblyForEVMObjects(langutil::EVMVersion _version); - static EVMDialect const& yulForEVM(langutil::EVMVersion _version); langutil::EVMVersion evmVersion() const { return m_evmVersion; } @@ -88,4 +87,23 @@ protected: std::map m_functions; }; +/** + * EVM dialect with types u256 (default) and bool. + * Difference to EVMDialect: + * - All comparison functions return type bool + * - bitwise operations are called bitor, bitand, bitxor and bitnot + * - and, or, xor take bool and return bool + * - iszero returns bool + * - isfalse takes bool and returns bool + * - there are conversion functions bool_to_u256 and u256_to_bool. + * - there is popbool + */ +struct EVMDialectTyped: public EVMDialect +{ + /// Constructor, should only be used internally. Use the factory function below. + EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectAccess); + + static EVMDialectTyped const& instance(langutil::EVMVersion _version); +}; + }