diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 9f233cfc0..645e6e61e 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -387,7 +387,7 @@ void CompilerContext::appendInlineAssembly( yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion); shared_ptr parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false); #ifdef SOL_OUTPUT_ASM - cout << yul::AsmPrinter()(*parserResult) << endl; + cout << yul::AsmPrinter(&dialect)(*parserResult) << endl; #endif auto reportError = [&](string const& _context) @@ -438,7 +438,7 @@ void CompilerContext::appendInlineAssembly( #ifdef SOL_OUTPUT_ASM cout << "After optimizer:" << endl; - cout << yul::AsmPrinter()(*parserResult) << endl; + cout << yul::AsmPrinter(&dialect)(*parserResult) << endl; #endif } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index fe3e2a7ef..16c11e3e7 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -892,6 +892,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) solAssert(holds_alternative(modified), ""); + // Do not provide dialect so that we get the full type information. m_code << yul::AsmPrinter()(std::get(std::move(modified))) << "\n"; return false; } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 148eeabfe..a117f8cd9 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -608,7 +608,7 @@ Scope& AsmAnalyzer::scope(Block const* _block) } void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location) { - if (!_type.empty() && !contains(m_dialect.types, _type)) + if (!_type.empty() && !m_dialect.types.count(_type)) m_errorReporter.typeError( _location, "\"" + _type.str() + "\" is not a valid type (user defined types are not yet supported)." diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 7ba122775..5a0f615d0 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -366,7 +366,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() location(), kind, YulString{currentLiteral()}, - {} + kind == LiteralKind::Boolean ? m_dialect.boolType : m_dialect.defaultType }; advance(); if (currentToken() == Token::Colon) @@ -497,6 +497,9 @@ TypedName Parser::parseTypedName() typedName.location.end = endPosition(); typedName.type = expectAsmIdentifier(); } + else + typedName.type = m_dialect.defaultType; + return typedName; } diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index a62db6123..93fb089ed 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -49,7 +50,7 @@ string AsmPrinter::operator()(Literal const& _literal) const return _literal.value.str() + appendTypeName(_literal.type); case LiteralKind::Boolean: yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, "Invalid bool literal."); - return ((_literal.value == "true"_yulstring) ? "true" : "false") + appendTypeName(_literal.type); + return ((_literal.value == "true"_yulstring) ? "true" : "false") + appendTypeName(_literal.type, true); case LiteralKind::String: break; } @@ -236,9 +237,18 @@ string AsmPrinter::formatTypedName(TypedName _variable) const return _variable.name.str() + appendTypeName(_variable.type); } -string AsmPrinter::appendTypeName(YulString _type) const +string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const { - if (!_type.empty()) + if (m_dialect && !_type.empty()) + { + if (!_isBoolLiteral && _type == m_dialect->defaultType) + _type = {}; + else if (_isBoolLiteral && _type == m_dialect->boolType && !m_dialect->defaultType.empty()) + // Special case: If we have a bool type but empty default type, do not remove the type. + _type = {}; + } + if (_type.empty()) + return {}; + else return ":" + _type.str(); - return ""; } diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 30569922d..f7ee9ff54 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -30,10 +30,16 @@ namespace solidity::yul { struct Dialect; +/** + * Converts a parsed Yul AST into readable string representation. + * Ignores source locations. + * If a dialect is provided, the dialect's default type is omitted. + */ class AsmPrinter { public: - explicit AsmPrinter() {} + AsmPrinter() {} + explicit AsmPrinter(Dialect const& _dialect): m_dialect(&_dialect) {} std::string operator()(Literal const& _literal) const; std::string operator()(Identifier const& _identifier) const; @@ -52,7 +58,9 @@ public: private: std::string formatTypedName(TypedName _variable) const; - std::string appendTypeName(YulString _type) const; + std::string appendTypeName(YulString _type, bool _isBoolLiteral = false) const; + + Dialect const* m_dialect = nullptr; }; } diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 35bcdf65c..9f7cc57a5 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -59,12 +59,12 @@ Dialect const& languageToDialect(AssemblyStack::Language _language, EVMVersion _ case AssemblyStack::Language::StrictAssembly: return EVMDialect::strictAssemblyForEVMObjects(_version); case AssemblyStack::Language::Yul: - return Dialect::yul(); + return EVMDialectTyped::instance(_version); case AssemblyStack::Language::Ewasm: return WasmDialect::instance(); } yulAssert(false, ""); - return Dialect::yul(); + return Dialect::yulDeprecated(); } } @@ -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."); @@ -236,7 +236,7 @@ string AssemblyStack::print() const { yulAssert(m_parserResult, ""); yulAssert(m_parserResult->code, ""); - return m_parserResult->toString(m_language == Language::Yul) + "\n"; + return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion)) + "\n"; } shared_ptr AssemblyStack::parserResult() const diff --git a/libyul/Dialect.cpp b/libyul/Dialect.cpp index fd9f54d0a..6bc056a75 100644 --- a/libyul/Dialect.cpp +++ b/libyul/Dialect.cpp @@ -23,7 +23,7 @@ using namespace solidity::yul; using namespace std; -Dialect const& Dialect::yul() +Dialect const& Dialect::yulDeprecated() { static unique_ptr dialect; static YulStringRepository::ResetCallback callback{[&] { dialect.reset(); }}; diff --git a/libyul/Dialect.h b/libyul/Dialect.h index b96e1851c..c25ba1ac3 100644 --- a/libyul/Dialect.h +++ b/libyul/Dialect.h @@ -48,10 +48,11 @@ struct BuiltinFunction struct Dialect: boost::noncopyable { + /// Default type, can be omitted. YulString defaultType; /// Type used for the literals "true" and "false". YulString boolType; - std::vector types; + std::set types; /// @returns the builtin function of the given name or a nullptr if it is not a builtin function. virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; } @@ -65,7 +66,8 @@ struct Dialect: boost::noncopyable Dialect() = default; virtual ~Dialect() = default; - static Dialect const& yul(); + /// Old "yul" dialect. This is only used for testing. + static Dialect const& yulDeprecated(); }; } diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 2d4a5e33a..13ad9f8ca 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -45,18 +45,18 @@ string indent(std::string const& _input) } -string Data::toString(bool) const +string Data::toString(Dialect const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; } -string Object::toString(bool _yul) const +string Object::toString(Dialect const* _dialect) const { yulAssert(code, "No code"); - string inner = "code " + AsmPrinter{}(*code); + string inner = "code " + (_dialect ? AsmPrinter{*_dialect} : AsmPrinter{})(*code); for (auto const& obj: subObjects) - inner += "\n" + obj->toString(_yul); + inner += "\n" + obj->toString(_dialect); return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; } diff --git a/libyul/Object.h b/libyul/Object.h index d7926d8bb..6ae79ed42 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -30,6 +30,7 @@ namespace solidity::yul { +struct Dialect; struct AsmAnalysisInfo; @@ -39,7 +40,8 @@ struct AsmAnalysisInfo; struct ObjectNode { virtual ~ObjectNode() = default; - virtual std::string toString(bool _yul) const = 0; + virtual std::string toString(Dialect const* _dialect) const = 0; + std::string toString() { return toString(nullptr); } YulString name; }; @@ -50,7 +52,7 @@ struct ObjectNode struct Data: ObjectNode { Data(YulString _name, bytes _data): data(std::move(_data)) { name = _name; } - std::string toString(bool _yul) const override; + std::string toString(Dialect const* _dialect) const override; bytes data; }; @@ -62,7 +64,7 @@ struct Object: ObjectNode { public: /// @returns a (parseable) string representation. Includes types if @a _yul is set. - std::string toString(bool _yul) const override; + std::string toString(Dialect const* _dialect) const override; /// @returns the set of names of data objects accessible from within the code of /// this object. diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 6e2407ced..3274f440f 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,77 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio evmasm::SemanticInformation::invalidatesMemory(_instruction) }; } + +EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectAccess): + EVMDialect(_evmVersion, _objectAccess) +{ + defaultType = "u256"_yulstring; + boolType = "bool"_yulstring; + types = {defaultType, boolType}; + + 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}; + + // "not" and "bitnot" replace "iszero" and "not" + m_functions["bitnot"_yulstring] = m_functions["not"_yulstring]; + m_functions["bitnot"_yulstring].name = "bitnot"_yulstring; + m_functions["not"_yulstring] = m_functions["iszero"_yulstring]; + m_functions["not"_yulstring].name = "not"_yulstring; + m_functions["not"_yulstring].returns = {"bool"_yulstring}; + m_functions["not"_yulstring].parameters = {"bool"_yulstring}; + m_functions.erase("iszero"_yulstring); + + m_functions["bitand"_yulstring] = m_functions["and"_yulstring]; + m_functions["bitand"_yulstring].name = "bitand"_yulstring; + m_functions["bitor"_yulstring] = m_functions["or"_yulstring]; + m_functions["bitor"_yulstring].name = "bitor"_yulstring; + m_functions["bitxor"_yulstring] = m_functions["xor"_yulstring]; + m_functions["bitxor"_yulstring].name = "bitxor"_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["popbool"_yulstring] = m_functions["pop"_yulstring]; + m_functions["popbool"_yulstring].name = "popbool"_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 + ) { + // A value larger than 1 causes an invalid instruction. + _visitArguments(); + _assembly.appendConstant(2); + _assembly.appendInstruction(evmasm::Instruction::DUP2); + _assembly.appendInstruction(evmasm::Instruction::LT); + AbstractAssembly::LabelID inRange = _assembly.newLabelId(); + _assembly.appendJumpToIf(inRange); + _assembly.appendInstruction(evmasm::Instruction::INVALID); + _assembly.appendLabel(inRange); + })); + 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..40842fa57 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,22 @@ 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 is replaced by not, which 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); +}; + } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 95e7bb315..754cd0bac 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -395,7 +395,9 @@ printTask "Testing assemble, yul, strict-assembly and optimize..." # Test yul and strict assembly output # Non-empty code results in non-empty binary representation with optimizations turned off, # while it results in empty binary representation with optimizations turned on. - test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x:u256 := 0:u256 }" "--yul" + test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x := 0 }" "--yul" + test_solc_assembly_output "{ let x:u256 := bitnot(7:u256) }" "{ let x := bitnot(7) }" "--yul" + test_solc_assembly_output "{ let t:bool := not(true) }" "{ let t:bool := not(true) }" "--yul" test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly" test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize" ) diff --git a/test/cmdlineTests/evm_to_wasm/output b/test/cmdlineTests/evm_to_wasm/output index 1c31f9488..a85239b23 100644 --- a/test/cmdlineTests/evm_to_wasm/output +++ b/test/cmdlineTests/evm_to_wasm/output @@ -15,9 +15,9 @@ object "object" { function main() { let _1 := 0 - mstore_internal(_1, _1, _1, _1, _1) + mstore_internal(0, _1, _1, _1, _1) mstore_internal(32, _1, _1, _1, 1) - eth.storageStore(_1, 32) + eth.storageStore(0, 32) } function endian_swap_16(x) -> y { @@ -45,7 +45,7 @@ object "object" { Binary representation: -0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021002000200020002000200010054220200020002000420110052000a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b +0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b Text representation: (module @@ -56,9 +56,9 @@ Text representation: (func $main (local $_1 i64) (local.set $_1 (i64.const 0)) - (call $mstore_internal (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) + (call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1)) - (call $eth.storageStore (i32.wrap_i64 (local.get $_1)) (i32.wrap_i64 (i64.const 32))) + (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) ) (func $endian_swap_16 diff --git a/test/cmdlineTests/standard_eWasm_requested/output.json b/test/cmdlineTests/standard_eWasm_requested/output.json index 11e7bb252..0652b99e4 100644 --- a/test/cmdlineTests/standard_eWasm_requested/output.json +++ b/test/cmdlineTests/standard_eWasm_requested/output.json @@ -10,21 +10,23 @@ (local $p i64) (local $r i64) (local $hi i64) - (local $y i64) (local $hi_1 i64) + (local $y i64) + (local $hi_2 i64) (local $_2 i64) (local.set $_1 (i64.const 0)) (local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64))) (local.set $r (i64.add (local.get $p) (i64.const 64))) (if (i64.ne (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $p))) (i64.const 0)) (then (unreachable))) - (local.set $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (local.get $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32))) - (local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32))))) + (local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16))) + (local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32))) + (local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32))))) (i64.store (i32.wrap_i64 (local.get $r)) (local.get $y)) (i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 8))) (local.get $y)) (i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 16))) (local.get $y)) - (local.set $hi_1 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32))) - (i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 24))) (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32))))) + (local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32))) + (i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 24))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32))))) (local.set $_2 (datasize \"C_2_deployed\")) (call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2)))) (call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2)))) @@ -37,9 +39,9 @@ (param $x4 i64) (result i64) (local $v i64) - (if (i64.ne (i64.extend_i32_u (i64.ne (local.get $v) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then (unreachable))) - (if (i64.ne (i64.extend_i32_u (i64.ne (local.get $v) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then (unreachable))) (local.set $v (local.get $x4)) (local.get $v) diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 6ea2bb63a..ff1517eec 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -48,7 +48,7 @@ namespace { Dialect const& defaultDialect(bool _yul) { - return _yul ? yul::Dialect::yul() : yul::EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()); + return _yul ? yul::Dialect::yulDeprecated() : yul::EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()); } } diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 95f7dd38f..8ec551258 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -49,7 +50,7 @@ namespace solidity::yul::test namespace { -bool parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorReporter) +shared_ptr parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorReporter) { try { @@ -58,18 +59,19 @@ bool parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorR if (parserResult) { yul::AsmAnalysisInfo analysisInfo; - return (yul::AsmAnalyzer( + if (yul::AsmAnalyzer( analysisInfo, errorReporter, _dialect - )).analyze(*parserResult); + ).analyze(*parserResult)) + return parserResult; } } catch (FatalError const&) { BOOST_FAIL("Fatal error leaked."); } - return false; + return {}; } std::optional parseAndReturnFirstError(string const& _source, Dialect const& _dialect, bool _allowWarnings = true) @@ -97,12 +99,12 @@ std::optional parseAndReturnFirstError(string const& _source, Dialect con return {}; } -bool successParse(std::string const& _source, Dialect const& _dialect = Dialect::yul(), bool _allowWarnings = true) +bool successParse(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarnings = true) { return !parseAndReturnFirstError(_source, _dialect, _allowWarnings); } -Error expectError(std::string const& _source, Dialect const& _dialect = Dialect::yul(), bool _allowWarnings = false) +Error expectError(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarnings = false) { auto error = parseAndReturnFirstError(_source, _dialect, _allowWarnings); @@ -120,7 +122,7 @@ do \ BOOST_CHECK(solidity::frontend::test::searchErrorMessage(err, (substring))); \ } while(0) -#define CHECK_ERROR(text, typ, substring) CHECK_ERROR_DIALECT(text, typ, substring, Dialect::yul()) +#define CHECK_ERROR(text, typ, substring) CHECK_ERROR_DIALECT(text, typ, substring, Dialect::yulDeprecated()) BOOST_AUTO_TEST_SUITE(YulParser) @@ -564,6 +566,50 @@ BOOST_AUTO_TEST_CASE(builtins_analysis) CHECK_ERROR_DIALECT("{ let a, b := builtin(1, 2) }", DeclarationError, "Variable count mismatch: 2 variables and 3 values.", dialect); } +BOOST_AUTO_TEST_CASE(default_types_set) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + shared_ptr result = parse( + "{" + "let x:bool := true:bool " + "let z:bool := true " + "let y := add(1, 2) " + "switch y case 0 {} default {} " + "}", + EVMDialectTyped::instance(EVMVersion{}), + reporter + ); + BOOST_REQUIRE(!!result); + + // Use no dialect so that all types are printed. + // This tests that the default types are properly assigned. + BOOST_CHECK_EQUAL(AsmPrinter{}(*result), + "{\n" + " let x:bool := true:bool\n" + " let z:bool := true:bool\n" + " let y:u256 := add(1:u256, 2:u256)\n" + " switch y\n" + " case 0:u256 { }\n" + " default { }\n" + "}" + ); + + // Now test again with type dialect. Now the default types + // should be omitted. + BOOST_CHECK_EQUAL(AsmPrinter{EVMDialectTyped::instance(EVMVersion{})}(*result), + "{\n" + " let x:bool := true\n" + " let z:bool := true\n" + " let y := add(1, 2)\n" + " switch y\n" + " case 0 { }\n" + " default { }\n" + "}" + ); +} + + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 609473acc..c4a6a48d6 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -105,7 +105,7 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) { auto dialectName = m_settings["dialect"]; if (dialectName == "yul") - m_dialect = &Dialect::yul(); + m_dialect = &Dialect::yulDeprecated(); else if (dialectName == "ewasm") m_dialect = &WasmDialect::instance(); else if (dialectName == "evm") @@ -365,7 +365,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line return TestResult::FatalError; } - m_obtainedResult = AsmPrinter{}(*m_ast) + "\n"; + m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n"; if (m_optimizerStep != m_validatedSettings["step"]) { diff --git a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul index 79b372972..ce79ef5e6 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul @@ -7,13 +7,13 @@ } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { -// { let a:u256, b:u256 } +// { let a, b } // { -// for { let a_1:u256 } a_1 { a_1 := a_1 } -// { let b_2:u256 := a_1 } +// for { let a_1 } a_1 { a_1 := a_1 } +// { let b_2 := a_1 } // } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul index fe54227d3..7a4cfe739 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul @@ -7,17 +7,13 @@ } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { +// { let a, b, c, d, f } // { -// let a:u256, b:u256, c:u256, d:u256, f:u256 -// } -// { -// function f_1(a_2:u256) -> c_3:u256, d_4:u256 -// { -// let b_5:u256, c_1:u256 := f_1(a_2) -// } +// function f_1(a_2) -> c_3, d_4 +// { let b_5, c_1 := f_1(a_2) } // } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul index 2dee55ae7..def0a2d31 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul @@ -6,11 +6,11 @@ } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { -// { let a:u256, b:u256, c:u256 } +// { let a, b, c } // { // let a_1:bool // if a_1 { let b_2:bool := a_1 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul index b5db97637..b403dc095 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul @@ -1,13 +1,13 @@ { { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { // { -// let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 +// let aanteuhdaoneudbrgkjiuaothduiathudaoeuh // } // { -// let aanteuhdaoneudbrgkjiuaothduiathudaoeuh_1:u256 +// let aanteuhdaoneudbrgkjiuaothduiathudaoeuh_1 // } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul index 647c78fda..0948b51b9 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul @@ -8,15 +8,15 @@ } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { -// { let a:u256, b:u256, c:u256 } +// { let a, b, c } // { -// let a_1:u256 +// let a_1 // switch a_1 -// case 0:u256 { let b_2:u256 := a_1 } -// default { let c_3:u256 := a_1 } +// case 0 { let b_2 := a_1 } +// default { let c_3 := a_1 } // } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables.yul b/test/libyul/yulOptimizerTests/disambiguator/variables.yul index 319809706..7b197f420 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables.yul @@ -1,9 +1,9 @@ { { let a:u256 } { let a:u256 } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { -// { let a:u256 } -// { let a_1:u256 } +// { let a } +// { let a_1 } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul index 9474dfc86..9c72b82ff 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul @@ -1,12 +1,12 @@ { { let a:u256 let a_1:u256 } { let a:u256 } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { // { -// let a:u256 -// let a_1:u256 +// let a +// let a_1 // } -// { let a_2:u256 } +// { let a_2 } // } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul index 66d36e431..fecb67a65 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul @@ -6,18 +6,18 @@ } } // ==== -// step: disambiguator // dialect: yul +// step: disambiguator // ---- // { // { -// let c:u256 -// let b:u256 +// let c +// let b // } -// function f(a:u256, c_1:u256) -> b_2:u256 -// { let x:u256 } +// function f(a, c_1) -> b_2 +// { let x } // { -// let a_3:u256 -// let x_4:u256 +// let a_3 +// let x_4 // } // } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul index c1a1c147e..8c3cd28e3 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul @@ -3,11 +3,11 @@ let y:u256 := f() } // ==== -// step: expressionInliner // dialect: yul +// step: expressionInliner // ---- // { -// function f() -> x:u256 -// { x := 2:u256 } -// let y:u256 := 2:u256 +// function f() -> x +// { x := 2 } +// let y := 2 // } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul index 8dd694aec..5b73ed3fe 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul @@ -3,11 +3,11 @@ let y:u256 := f(7:u256) } // ==== -// step: expressionInliner // dialect: yul +// step: expressionInliner // ---- // { -// function f(a:u256) -> x:u256 +// function f(a) -> x // { x := a } -// let y:u256 := 7:u256 +// let y := 7 // } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul index 950118647..f08de996b 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul @@ -1,16 +1,16 @@ { let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } } // ==== -// step: functionGrouper // dialect: yul +// step: functionGrouper // ---- // { // { -// let a:u256 +// let a // { } // } // function f() -> x:bool // { -// let b:u256 := 4:u256 +// let b := 4 // { } // for { } f() { } // { } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul index 559452a98..5fb398ad7 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul @@ -5,17 +5,17 @@ let e:u256 } // ==== -// step: functionGrouper // dialect: yul +// step: functionGrouper // ---- // { // { -// let a:u256 -// let c:u256 -// let e:u256 +// let a +// let c +// let e // } // function f() -// { let b:u256 } +// { let b } // function g() -// { let d:u256 } +// { let d } // } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul index 14b28fbab..455da2ef5 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul @@ -9,16 +9,16 @@ } } // ==== -// step: functionGrouper // dialect: yul +// step: functionGrouper // ---- // { -// { let a:u256 } +// { let a } // function f() // { -// let b:u256 +// let b // function g() -// { let c:u256 } -// let d:u256 +// { let c } +// let d // } // } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul index 94af92287..f7836b6c6 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul @@ -2,11 +2,11 @@ let a:u256 function f() {} } // ==== -// step: functionGrouper // dialect: yul +// step: functionGrouper // ---- // { -// { let a:u256 } +// { let a } // function f() // { } // } diff --git a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul index 4a7c0a7a2..276fd4b02 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul @@ -8,14 +8,14 @@ } } // ==== -// step: functionHoister // dialect: yul +// step: functionHoister // ---- // { -// let a:u256 +// let a // function f() -> x:bool // { -// let b:u256 := 4:u256 +// let b := 4 // for { } f() { } // { } // } diff --git a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul index 78e4b49ab..4e9e9604f 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul @@ -6,15 +6,15 @@ let e:u256 } // ==== -// step: functionHoister // dialect: yul +// step: functionHoister // ---- // { -// let a:u256 -// let c:u256 -// let e:u256 +// let a +// let c +// let e // function f() -// { let b:u256 } +// { let b } // function g() -// { let d:u256 } +// { let d } // } diff --git a/test/libyul/yulOptimizerTests/functionHoister/nested.yul b/test/libyul/yulOptimizerTests/functionHoister/nested.yul index 813598503..89ea5c0ff 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/nested.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/nested.yul @@ -7,16 +7,16 @@ } } // ==== -// step: functionHoister // dialect: yul +// step: functionHoister // ---- // { -// let a:u256 +// let a // function g() -// { let c:u256 } +// { let c } // function f() // { -// let b:u256 -// let d:u256 +// let b +// let d // } // } diff --git a/test/libyul/yulOptimizerTests/functionHoister/single.yul b/test/libyul/yulOptimizerTests/functionHoister/single.yul index 70ecfdb8e..6cc82e68a 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/single.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/single.yul @@ -3,11 +3,11 @@ function f() {} } // ==== -// step: functionHoister // dialect: yul +// step: functionHoister // ---- // { -// let a:u256 +// let a // function f() // { } // } diff --git a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul index 09a04e1d3..741efd42b 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul @@ -8,18 +8,18 @@ } } // ==== -// step: mainFunction // dialect: yul +// step: mainFunction // ---- // { // function main() // { -// let a:u256 +// let a // { } // } // function f() -> x:bool // { -// let b:u256 := 4:u256 +// let b := 4 // { } // for { } f() { } // { } diff --git a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul index 7aaab11e5..69fb0bef0 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul @@ -6,18 +6,18 @@ let e:u256 } // ==== -// step: mainFunction // dialect: yul +// step: mainFunction // ---- // { // function main() // { -// let a:u256 -// let c:u256 -// let e:u256 +// let a +// let c +// let e // } // function f() -// { let b:u256 } +// { let b } // function g() -// { let d:u256 } +// { let d } // } diff --git a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul index 61cb67233..b97bb2f4d 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul @@ -7,17 +7,17 @@ } } // ==== -// step: mainFunction // dialect: yul +// step: mainFunction // ---- // { // function main() -// { let a:u256 } +// { let a } // function f() // { -// let b:u256 +// let b // function g() -// { let c:u256 } -// let d:u256 +// { let c } +// let d // } // } diff --git a/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul similarity index 87% rename from test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul rename to test/libyul/yulOptimizerTests/mainFunction/single_fun.yul index 63154e8c3..1ab108f6b 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/sigle_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul @@ -3,12 +3,12 @@ function f() {} } // ==== -// step: mainFunction // dialect: yul +// step: mainFunction // ---- // { // function main() -// { let a:u256 } +// { let a } // function f() // { } // } diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 23e535734..998c25bae 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -248,7 +248,7 @@ public: default: cout << "Unknown option." << endl; } - source = AsmPrinter{}(*m_ast); + source = AsmPrinter{m_dialect}(*m_ast); } }