diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 42b81d34b..bc5fe880d 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -606,6 +606,9 @@ string YulUtilFunctions::allocationFunction() string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) { + if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) + return conversionFunctionSpecial(_from, _to); + string functionName = "convert_" + _from.identifier() + @@ -923,3 +926,69 @@ string YulUtilFunctions::suffixedVariableNameList(string const& _baseName, size_ } return result; } + +string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to) +{ + string functionName = + "convert_" + + _from.identifier() + + "_to_" + + _to.identifier(); + return m_functionCollector->createFunction(functionName, [&]() { + solUnimplementedAssert( + _from.category() == Type::Category::StringLiteral, + "Type conversion " + _from.toString() + " -> " + _to.toString() + " not yet implemented." + ); + string const& data = dynamic_cast(_from).value(); + if (_to.category() == Type::Category::FixedBytes) + { + unsigned const numBytes = dynamic_cast(_to).numBytes(); + solAssert(data.size() <= 32, ""); + Whiskers templ(R"( + function () -> converted { + converted := + } + )"); + templ("functionName", functionName); + templ("data", formatNumber( + h256::Arith(h256(data, h256::AlignLeft)) & + (~(u256(-1) >> (8 * numBytes))) + )); + return templ.render(); + } + else if (_to.category() == Type::Category::Array) + { + auto const& arrayType = dynamic_cast(_to); + solAssert(arrayType.isByteArray(), ""); + size_t words = (data.size() + 31) / 32; + size_t storageSize = 32 + words * 32; + + Whiskers templ(R"( + function () -> converted { + converted := () + mstore(converted, ) + <#word> + mstore(add(converted, ), ) + + } + )"); + templ("functionName", functionName); + templ("allocate", allocationFunction()); + templ("storageSize", to_string(storageSize)); + templ("size", to_string(data.size())); + vector> wordParams(words); + for (size_t i = 0; i < words; ++i) + { + wordParams[i]["offset"] = to_string(32 + i * 32); + wordParams[i]["wordValue"] = "0x" + h256(data.substr(32 * i, 32), h256::AlignLeft).hex(); + } + templ("word", wordParams); + return templ.render(); + } + else + solAssert( + false, + "Invalid conversion from string literal to " + _to.toString() + " requested." + ); + }); +} diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index cca8ec209..b3c29dcfc 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -155,6 +155,11 @@ public: static std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix); private: + + /// Special case of conversionFunction - handles everything that does not + /// use exactly one variable to hold the value. + std::string conversionFunctionSpecial(Type const& _from, Type const& _to); + langutil::EVMVersion m_evmVersion; std::shared_ptr m_functionCollector; }; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 8b1f4a4a5..53c0586ea 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -357,7 +357,6 @@ bool IRGeneratorForStatements::visit(Literal const& _literal) defineExpression(_literal) << toCompactHexWithPrefix(literalType.literalValue(&_literal)) << "\n"; break; case Type::Category::StringLiteral: - solUnimplemented(""); break; // will be done during conversion default: solUnimplemented("Only integer, boolean and string literals implemented for now."); @@ -368,12 +367,20 @@ bool IRGeneratorForStatements::visit(Literal const& _literal) string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) { Type const& from = type(_expression); - string varName = m_context.variable(_expression); - - if (from == _to) - return varName; + if (from.sizeOnStack() == 0) + { + solAssert(from != _to, ""); + return m_utils.conversionFunction(from, _to) + "()"; + } else - return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")"; + { + string varName = m_context.variable(_expression); + + if (from == _to) + return varName; + else + return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")"; + } } ostream& IRGeneratorForStatements::defineExpression(Expression const& _expression)