From c1ca16cd33242cf3581fe4986b41003675303e65 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 24 Apr 2019 23:48:12 +0200 Subject: [PATCH 1/5] Implement return. --- libsolidity/codegen/ir/IRGenerator.cpp | 9 ++++++- .../codegen/ir/IRGeneratorForStatements.cpp | 24 +++++++++++++++++-- .../output.json | 2 +- .../standard_ir_requested/output.json | 2 +- .../semanticTests/viaYul/return.sol | 10 ++++++++ .../viaYul/return_and_convert.sol | 11 +++++++++ 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/return.sol create mode 100644 test/libsolidity/semanticTests/viaYul/return_and_convert.sol diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 9b1ad3413..a2bea3992 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -116,7 +116,14 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) { string functionName = m_context.functionName(_function); return m_context.functionCollector()->createFunction(functionName, [&]() { - Whiskers t("\nfunction () {\n\n}\n"); + Whiskers t(R"( + function () { + for { let return_flag := 1 } return_flag {} { + + break + } + } + )"); t("functionName", functionName); string params; for (auto const& varDecl: _function.parameters()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 42d92fbd5..39fd826ab 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -126,9 +126,29 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) return false; } -bool IRGeneratorForStatements::visit(Return const&) +bool IRGeneratorForStatements::visit(Return const& _return) { - solUnimplemented("Return not yet implemented in yul code generation"); + if (Expression const* value = _return.expression()) + { + solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer."); + vector> const& returnParameters = + _return.annotation().functionReturnParameters->parameters(); + TypePointers types; + for (auto const& retVariable: returnParameters) + types.push_back(retVariable->annotation().type); + + value->accept(*this); + + // TODO support tuples + solUnimplementedAssert(types.size() == 1, "Multi-returns not implemented."); + m_code << + m_context.variableName(*returnParameters.front()) << + " := " << + expressionAsType(*value, *types.front()) << + "\n"; + } + m_code << "return_flag := 0\n" << "break\n"; + return false; } void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 5fb828a66..99e13e010 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -1 +1 @@ -{"contracts":{"A":{"C":{"irOptimized":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\nobject \"C_6\" {\n code {\n mstore(64, 128)\n codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n return(0, datasize(\"C_6_deployed\"))\n }\n object \"C_6_deployed\" {\n code {\n mstore(64, 128)\n if iszero(lt(calldatasize(), 4))\n {\n let selector := shift_right_224_unsigned(calldataload(0))\n switch selector\n case 0x26121ff0 {\n if callvalue()\n {\n revert(0, 0)\n }\n abi_decode_tuple_(4, calldatasize())\n fun_f_5()\n let memPos := allocateMemory(0)\n let memEnd := abi_encode_tuple__to__fromStack(memPos)\n return(memPos, sub(memEnd, memPos))\n }\n default {\n }\n }\n revert(0, 0)\n function abi_decode_tuple_(headStart, dataEnd)\n {\n if slt(sub(dataEnd, headStart), 0)\n {\n revert(0, 0)\n }\n }\n function abi_encode_tuple__to__fromStack(headStart) -> tail\n {\n tail := add(headStart, 0)\n }\n function allocateMemory(size) -> memPtr\n {\n memPtr := mload(64)\n let newFreePtr := add(memPtr, size)\n if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr))\n {\n revert(0, 0)\n }\n mstore(64, newFreePtr)\n }\n function fun_f_5()\n {\n }\n function shift_right_224_unsigned(value) -> newValue\n {\n newValue := shr(224, value)\n }\n }\n }\n}\n"}}},"sources":{"A":{"id":0}}} +{"contracts":{"A":{"C":{"irOptimized":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\nobject \"C_6\" {\n code {\n mstore(64, 128)\n codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n return(0, datasize(\"C_6_deployed\"))\n }\n object \"C_6_deployed\" {\n code {\n mstore(64, 128)\n if iszero(lt(calldatasize(), 4))\n {\n let selector := shift_right_224_unsigned(calldataload(0))\n switch selector\n case 0x26121ff0 {\n if callvalue()\n {\n revert(0, 0)\n }\n abi_decode_tuple_(4, calldatasize())\n fun_f_5()\n let memPos := allocateMemory(0)\n let memEnd := abi_encode_tuple__to__fromStack(memPos)\n return(memPos, sub(memEnd, memPos))\n }\n default {\n }\n }\n revert(0, 0)\n function abi_decode_tuple_(headStart, dataEnd)\n {\n if slt(sub(dataEnd, headStart), 0)\n {\n revert(0, 0)\n }\n }\n function abi_encode_tuple__to__fromStack(headStart) -> tail\n {\n tail := add(headStart, 0)\n }\n function allocateMemory(size) -> memPtr\n {\n memPtr := mload(64)\n let newFreePtr := add(memPtr, size)\n if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr))\n {\n revert(0, 0)\n }\n mstore(64, newFreePtr)\n }\n function fun_f_5()\n {\n for {\n let return_flag := 1\n }\n return_flag\n {\n }\n {\n break\n }\n }\n function shift_right_224_unsigned(value) -> newValue\n {\n newValue := shr(224, value)\n }\n }\n }\n}\n"}}},"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index ddca38e62..5498331dd 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -1 +1 @@ -{"contracts":{"A":{"C":{"ir":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\n\n\t\tobject \"C_6\" {\n\t\t\tcode {\n\t\t\t\tmstore(64, 128)\n\t\t\t\t\n\t\t\t\t\n\t\tcodecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n\t\treturn(0, datasize(\"C_6_deployed\"))\n\t\n\t\t\t\t\n\t\t\t}\n\t\t\tobject \"C_6_deployed\" {\n\t\t\t\tcode {\n\t\t\t\t\tmstore(64, 128)\n\t\t\t\t\t\n\t\tif iszero(lt(calldatasize(), 4))\n\t\t{\n\t\t\tlet selector := shift_right_224_unsigned(calldataload(0))\n\t\t\tswitch selector\n\t\t\t\n\t\t\tcase 0x26121ff0\n\t\t\t{\n\t\t\t\t// f()\n\t\t\t\tif callvalue() { revert(0, 0) }\n\t\t\t\t abi_decode_tuple_(4, calldatasize())\n\t\t\t\t fun_f_5()\n\t\t\t\tlet memPos := allocateMemory(0)\n\t\t\t\tlet memEnd := abi_encode_tuple__to__fromStack(memPos )\n\t\t\t\treturn(memPos, sub(memEnd, memPos))\n\t\t\t}\n\t\t\t\n\t\t\tdefault {}\n\t\t}\n\t\trevert(0, 0)\n\t\n\t\t\t\t\t\n\t\t\tfunction abi_decode_tuple_(headStart, dataEnd) {\n\t\t\t\tif slt(sub(dataEnd, headStart), 0) { revert(0, 0) }\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction abi_encode_tuple__to__fromStack(headStart ) -> tail {\n\t\t\t\ttail := add(headStart, 0)\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction allocateMemory(size) -> memPtr {\n\t\t\t\tmemPtr := mload(64)\n\t\t\t\tlet newFreePtr := add(memPtr, size)\n\t\t\t\t// protect against overflow\n\t\t\t\tif or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }\n\t\t\t\tmstore(64, newFreePtr)\n\t\t\t}\n\t\t\nfunction fun_f_5() {\n\n}\n\n\t\t\t\tfunction shift_right_224_unsigned(value) -> newValue {\n\t\t\t\t\tnewValue := shr(224, value)\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t"}}},"sources":{"A":{"id":0}}} +{"contracts":{"A":{"C":{"ir":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\n\n\t\tobject \"C_6\" {\n\t\t\tcode {\n\t\t\t\tmstore(64, 128)\n\t\t\t\t\n\t\t\t\t\n\t\tcodecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n\t\treturn(0, datasize(\"C_6_deployed\"))\n\t\n\t\t\t\t\n\t\t\t}\n\t\t\tobject \"C_6_deployed\" {\n\t\t\t\tcode {\n\t\t\t\t\tmstore(64, 128)\n\t\t\t\t\t\n\t\tif iszero(lt(calldatasize(), 4))\n\t\t{\n\t\t\tlet selector := shift_right_224_unsigned(calldataload(0))\n\t\t\tswitch selector\n\t\t\t\n\t\t\tcase 0x26121ff0\n\t\t\t{\n\t\t\t\t// f()\n\t\t\t\tif callvalue() { revert(0, 0) }\n\t\t\t\t abi_decode_tuple_(4, calldatasize())\n\t\t\t\t fun_f_5()\n\t\t\t\tlet memPos := allocateMemory(0)\n\t\t\t\tlet memEnd := abi_encode_tuple__to__fromStack(memPos )\n\t\t\t\treturn(memPos, sub(memEnd, memPos))\n\t\t\t}\n\t\t\t\n\t\t\tdefault {}\n\t\t}\n\t\trevert(0, 0)\n\t\n\t\t\t\t\t\n\t\t\tfunction abi_decode_tuple_(headStart, dataEnd) {\n\t\t\t\tif slt(sub(dataEnd, headStart), 0) { revert(0, 0) }\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction abi_encode_tuple__to__fromStack(headStart ) -> tail {\n\t\t\t\ttail := add(headStart, 0)\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction allocateMemory(size) -> memPtr {\n\t\t\t\tmemPtr := mload(64)\n\t\t\t\tlet newFreePtr := add(memPtr, size)\n\t\t\t\t// protect against overflow\n\t\t\t\tif or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }\n\t\t\t\tmstore(64, newFreePtr)\n\t\t\t}\n\t\t\n\t\t\tfunction fun_f_5() {\n\t\t\t\tfor { let return_flag := 1 } return_flag {} {\n\t\t\t\t\t\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\t\tfunction shift_right_224_unsigned(value) -> newValue {\n\t\t\t\t\tnewValue := shr(224, value)\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t"}}},"sources":{"A":{"id":0}}} diff --git a/test/libsolidity/semanticTests/viaYul/return.sol b/test/libsolidity/semanticTests/viaYul/return.sol new file mode 100644 index 000000000..32a21ae76 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/return.sol @@ -0,0 +1,10 @@ +contract C { + function f() public pure returns (uint x) { + return 7; + x = 3; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/viaYul/return_and_convert.sol b/test/libsolidity/semanticTests/viaYul/return_and_convert.sol new file mode 100644 index 000000000..613184aa9 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/return_and_convert.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure returns (uint) { + uint8 b; + assembly { b := 0xffff } + return b; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 255 From 597d37b7315f5ffcb7d99b90710b0e583b3ebf34 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Apr 2019 00:01:13 +0200 Subject: [PATCH 2/5] Implement for loops. --- .../codegen/ir/IRGeneratorForStatements.cpp | 37 +++++++++++++++++++ .../codegen/ir/IRGeneratorForStatements.h | 3 ++ 2 files changed, 40 insertions(+) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 39fd826ab..1fad14494 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -126,6 +127,42 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) return false; } +bool IRGeneratorForStatements::visit(ForStatement const& _for) +{ + m_code << "for {\n"; + if (_for.initializationExpression()) + _for.initializationExpression()->accept(*this); + m_code << "} return_flag {\n"; + if (_for.loopExpression()) + _for.loopExpression()->accept(*this); + m_code << "}\n"; + if (_for.condition()) + { + _for.condition()->accept(*this); + m_code << + "if iszero(" << + expressionAsType(*_for.condition(), *TypeProvider::boolean()) << + ") { break }\n"; + } + _for.body().accept(*this); + m_code << "}\n"; + // Bubble up the return condition. + m_code << "if iszero(return_flag) { break }\n"; + return false; +} + +bool IRGeneratorForStatements::visit(Continue const&) +{ + m_code << "continue\n"; + return false; +} + +bool IRGeneratorForStatements::visit(Break const&) +{ + m_code << "break\n"; + return false; +} + bool IRGeneratorForStatements::visit(Return const& _return) { if (Expression const* value = _return.expression()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b40d50ff4..331962f84 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -46,6 +46,9 @@ public: bool visit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Assignment const& _assignment) override; + bool visit(ForStatement const& _forStatement) override; + bool visit(Continue const& _continueStatement) override; + bool visit(Break const& _breakStatement) override; bool visit(Return const& _return) override; void endVisit(BinaryOperation const& _binOp) override; bool visit(FunctionCall const& _funCall) override; From 0eef51ffa4f888d40f20926d97079fa573cbed7c Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Apr 2019 00:10:29 +0200 Subject: [PATCH 3/5] Conversion during binary operation. --- .../codegen/ir/IRGeneratorForStatements.cpp | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1fad14494..1e9ac5c34 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -190,24 +190,39 @@ bool IRGeneratorForStatements::visit(Return const& _return) void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) { - solUnimplementedAssert(_binOp.getOperator() == Token::Add, ""); - solUnimplementedAssert(*_binOp.leftExpression().annotation().type == *_binOp.rightExpression().annotation().type, ""); - if (IntegerType const* type = dynamic_cast(_binOp.annotation().commonType)) - { - solUnimplementedAssert(!type->isSigned(), ""); + solAssert(!!_binOp.annotation().commonType, ""); + TypePointer commonType = _binOp.annotation().commonType; + + if (_binOp.getOperator() == Token::And || _binOp.getOperator() == Token::Or) + // special case: short-circuiting + solUnimplementedAssert(false, ""); + else if (commonType->category() == Type::Category::RationalNumber) m_code << "let " << m_context.variable(_binOp) << " := " << - m_utils.overflowCheckedUIntAddFunction(type->numBits()) << - "(" << - m_context.variable(_binOp.leftExpression()) << - ", " << - m_context.variable(_binOp.rightExpression()) << - ")\n"; - } + toCompactHexWithPrefix(commonType->literalValue(nullptr)) << + "\n"; else - solUnimplementedAssert(false, ""); + { + solUnimplementedAssert(_binOp.getOperator() == Token::Add, ""); + if (IntegerType const* type = dynamic_cast(commonType)) + { + solUnimplementedAssert(!type->isSigned(), ""); + m_code << + "let " << + m_context.variable(_binOp) << + " := " << + m_utils.overflowCheckedUIntAddFunction(type->numBits()) << + "(" << + expressionAsType(_binOp.leftExpression(), *commonType) << + ", " << + expressionAsType(_binOp.rightExpression(), *commonType) << + ")\n"; + } + else + solUnimplementedAssert(false, ""); + } } bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) From e66ab6c036c96e2f2f0fb1952b1115b0a2ff0d1e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 25 Apr 2019 00:21:00 +0200 Subject: [PATCH 4/5] Helper function to define the value of expressions. --- .../codegen/ir/IRGeneratorForStatements.cpp | 36 +++++++------------ .../codegen/ir/IRGeneratorForStatements.h | 1 + 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1e9ac5c34..57fecc061 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -122,7 +122,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) " := " << expressionAsType(_assignment.rightHandSide(), *lvalue.annotation().type) << "\n"; - m_code << "let " << m_context.variable(_assignment) << " := " << varName << "\n"; + defineExpression(_assignment) << varName << "\n"; return false; } @@ -197,10 +197,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) // special case: short-circuiting solUnimplementedAssert(false, ""); else if (commonType->category() == Type::Category::RationalNumber) - m_code << - "let " << - m_context.variable(_binOp) << - " := " << + defineExpression(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; else @@ -209,10 +206,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) if (IntegerType const* type = dynamic_cast(commonType)) { solUnimplementedAssert(!type->isSigned(), ""); - m_code << - "let " << - m_context.variable(_binOp) << - " := " << + defineExpression(_binOp) << m_utils.overflowCheckedUIntAddFunction(type->numBits()) << "(" << expressionAsType(_binOp.leftExpression(), *commonType) << @@ -241,10 +235,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) solAssert(_functionCall.arguments().size() == 1, "Expected one argument for type conversion"); _functionCall.arguments().front()->accept(*this); - m_code << - "let " << - m_context.variable(_functionCall) << - " := " << + defineExpression(_functionCall) << expressionAsType(*_functionCall.arguments().front(), *_functionCall.annotation().type) << "\n"; @@ -297,10 +288,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) if (auto functionDef = dynamic_cast(identifier->annotation().referencedDeclaration)) { // @TODO The function can very well return multiple vars. - m_code << - "let " << - m_context.variable(_functionCall) << - " := " << + defineExpression(_functionCall) << m_context.virtualFunctionName(*functionDef) << "(" << joinHumanReadable(args) << @@ -313,10 +301,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) // @TODO The function can very well return multiple vars. args = vector{m_context.variable(_functionCall.expression())} + args; - m_code << - "let " << - m_context.variable(_functionCall) << - " := " << + defineExpression(_functionCall) << m_context.internalDispatch(functionType->parameterTypes().size(), functionType->returnParameterTypes().size()) << "(" << joinHumanReadable(args) << @@ -351,7 +336,7 @@ bool IRGeneratorForStatements::visit(Identifier const& _identifier) value = m_context.variableName(*varDecl); else solUnimplemented(""); - m_code << "let " << m_context.variable(_identifier) << " := " << value << "\n"; + defineExpression(_identifier) << value << "\n"; return false; } @@ -364,7 +349,7 @@ bool IRGeneratorForStatements::visit(Literal const& _literal) case Type::Category::RationalNumber: case Type::Category::Bool: case Type::Category::Address: - m_code << "let " << m_context.variable(_literal) << " := " << toCompactHexWithPrefix(type->literalValue(&_literal)) << "\n"; + defineExpression(_literal) << toCompactHexWithPrefix(type->literalValue(&_literal)) << "\n"; break; case Type::Category::StringLiteral: solUnimplemented(""); @@ -385,3 +370,8 @@ string IRGeneratorForStatements::expressionAsType(Expression const& _expression, else return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")"; } + +ostream& IRGeneratorForStatements::defineExpression(Expression const& _expression) +{ + return m_code << "let " << m_context.variable(_expression) << " := "; +} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 331962f84..5f5259463 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -60,6 +60,7 @@ private: /// @returns a Yul expression representing the current value of @a _expression, /// converted to type @a _to if it does not yet have that type. std::string expressionAsType(Expression const& _expression, Type const& _to); + std::ostream& defineExpression(Expression const& _expression); std::ostringstream m_code; IRGenerationContext& m_context; From bab2391a7cb5b3a823d8164073e0d307e7e23895 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 29 Apr 2019 16:38:18 +0200 Subject: [PATCH 5/5] Test case for loops. --- .../semanticTests/viaYul/loops.sol | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 test/libsolidity/semanticTests/viaYul/loops.sol diff --git a/test/libsolidity/semanticTests/viaYul/loops.sol b/test/libsolidity/semanticTests/viaYul/loops.sol new file mode 100644 index 000000000..02cefc021 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/loops.sol @@ -0,0 +1,40 @@ +contract C { + function f() public returns (uint x) { + x = 1; + for (uint a = 0; a < 10; a = a + 1) { + x = x + x; + } + } + function g() public returns (uint x) { + x = 1; + for (uint a = 0; a < 10; a = a + 1) { + x = x + x; + break; + } + } + function h() public returns (uint x) { + x = 1; + uint a = 0; + for (; a < 10; a = a + 1) { + continue; + x = x + x; + } + x = x + a; + } + function i() public returns (uint x) { + x = 1; + uint a; + for (; a < 10; a = a + 1) { + return x; + x = x + x; + } + x = x + a; + } +} +// === +// compileViaYul: true +// ---- +// f() -> 1024 +// g() -> 2 +// h() -> 11 +// i() -> 1