mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6589 from ethereum/addReturn
[Yul] Add code generation for "return" and for loops.
This commit is contained in:
commit
dc13469593
@ -116,7 +116,14 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
string functionName = m_context.functionName(_function);
|
string functionName = m_context.functionName(_function);
|
||||||
return m_context.functionCollector()->createFunction(functionName, [&]() {
|
return m_context.functionCollector()->createFunction(functionName, [&]() {
|
||||||
Whiskers t("\nfunction <functionName>(<params>) <returns> {\n<body>\n}\n");
|
Whiskers t(R"(
|
||||||
|
function <functionName>(<params>) <returns> {
|
||||||
|
for { let return_flag := 1 } return_flag {} {
|
||||||
|
<body>
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)");
|
||||||
t("functionName", functionName);
|
t("functionName", functionName);
|
||||||
string params;
|
string params;
|
||||||
for (auto const& varDecl: _function.parameters())
|
for (auto const& varDecl: _function.parameters())
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
#include <libsolidity/codegen/ir/IRGenerationContext.h>
|
||||||
#include <libsolidity/codegen/YulUtilFunctions.h>
|
#include <libsolidity/codegen/YulUtilFunctions.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
#include <libyul/AsmPrinter.h>
|
#include <libyul/AsmPrinter.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
@ -121,36 +122,101 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
|||||||
" := " <<
|
" := " <<
|
||||||
expressionAsType(_assignment.rightHandSide(), *lvalue.annotation().type) <<
|
expressionAsType(_assignment.rightHandSide(), *lvalue.annotation().type) <<
|
||||||
"\n";
|
"\n";
|
||||||
m_code << "let " << m_context.variable(_assignment) << " := " << varName << "\n";
|
defineExpression(_assignment) << varName << "\n";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRGeneratorForStatements::visit(Return const&)
|
bool IRGeneratorForStatements::visit(ForStatement const& _for)
|
||||||
{
|
{
|
||||||
solUnimplemented("Return not yet implemented in yul code generation");
|
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())
|
||||||
|
{
|
||||||
|
solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
|
||||||
|
vector<ASTPointer<VariableDeclaration>> 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)
|
void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
|
solAssert(!!_binOp.annotation().commonType, "");
|
||||||
solUnimplementedAssert(*_binOp.leftExpression().annotation().type == *_binOp.rightExpression().annotation().type, "");
|
TypePointer commonType = _binOp.annotation().commonType;
|
||||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(_binOp.annotation().commonType))
|
|
||||||
{
|
if (_binOp.getOperator() == Token::And || _binOp.getOperator() == Token::Or)
|
||||||
solUnimplementedAssert(!type->isSigned(), "");
|
// special case: short-circuiting
|
||||||
m_code <<
|
|
||||||
"let " <<
|
|
||||||
m_context.variable(_binOp) <<
|
|
||||||
" := " <<
|
|
||||||
m_utils.overflowCheckedUIntAddFunction(type->numBits()) <<
|
|
||||||
"(" <<
|
|
||||||
m_context.variable(_binOp.leftExpression()) <<
|
|
||||||
", " <<
|
|
||||||
m_context.variable(_binOp.rightExpression()) <<
|
|
||||||
")\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
solUnimplementedAssert(false, "");
|
solUnimplementedAssert(false, "");
|
||||||
|
else if (commonType->category() == Type::Category::RationalNumber)
|
||||||
|
defineExpression(_binOp) <<
|
||||||
|
toCompactHexWithPrefix(commonType->literalValue(nullptr)) <<
|
||||||
|
"\n";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
|
||||||
|
if (IntegerType const* type = dynamic_cast<IntegerType const*>(commonType))
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(!type->isSigned(), "");
|
||||||
|
defineExpression(_binOp) <<
|
||||||
|
m_utils.overflowCheckedUIntAddFunction(type->numBits()) <<
|
||||||
|
"(" <<
|
||||||
|
expressionAsType(_binOp.leftExpression(), *commonType) <<
|
||||||
|
", " <<
|
||||||
|
expressionAsType(_binOp.rightExpression(), *commonType) <<
|
||||||
|
")\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solUnimplementedAssert(false, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||||
@ -169,10 +235,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
|||||||
solAssert(_functionCall.arguments().size() == 1, "Expected one argument for type conversion");
|
solAssert(_functionCall.arguments().size() == 1, "Expected one argument for type conversion");
|
||||||
_functionCall.arguments().front()->accept(*this);
|
_functionCall.arguments().front()->accept(*this);
|
||||||
|
|
||||||
m_code <<
|
defineExpression(_functionCall) <<
|
||||||
"let " <<
|
|
||||||
m_context.variable(_functionCall) <<
|
|
||||||
" := " <<
|
|
||||||
expressionAsType(*_functionCall.arguments().front(), *_functionCall.annotation().type) <<
|
expressionAsType(*_functionCall.arguments().front(), *_functionCall.annotation().type) <<
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
@ -225,10 +288,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
|||||||
if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||||
{
|
{
|
||||||
// @TODO The function can very well return multiple vars.
|
// @TODO The function can very well return multiple vars.
|
||||||
m_code <<
|
defineExpression(_functionCall) <<
|
||||||
"let " <<
|
|
||||||
m_context.variable(_functionCall) <<
|
|
||||||
" := " <<
|
|
||||||
m_context.virtualFunctionName(*functionDef) <<
|
m_context.virtualFunctionName(*functionDef) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
joinHumanReadable(args) <<
|
joinHumanReadable(args) <<
|
||||||
@ -241,10 +301,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
// @TODO The function can very well return multiple vars.
|
// @TODO The function can very well return multiple vars.
|
||||||
args = vector<string>{m_context.variable(_functionCall.expression())} + args;
|
args = vector<string>{m_context.variable(_functionCall.expression())} + args;
|
||||||
m_code <<
|
defineExpression(_functionCall) <<
|
||||||
"let " <<
|
|
||||||
m_context.variable(_functionCall) <<
|
|
||||||
" := " <<
|
|
||||||
m_context.internalDispatch(functionType->parameterTypes().size(), functionType->returnParameterTypes().size()) <<
|
m_context.internalDispatch(functionType->parameterTypes().size(), functionType->returnParameterTypes().size()) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
joinHumanReadable(args) <<
|
joinHumanReadable(args) <<
|
||||||
@ -279,7 +336,7 @@ bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
|||||||
value = m_context.variableName(*varDecl);
|
value = m_context.variableName(*varDecl);
|
||||||
else
|
else
|
||||||
solUnimplemented("");
|
solUnimplemented("");
|
||||||
m_code << "let " << m_context.variable(_identifier) << " := " << value << "\n";
|
defineExpression(_identifier) << value << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +349,7 @@ bool IRGeneratorForStatements::visit(Literal const& _literal)
|
|||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
case Type::Category::Address:
|
case Type::Category::Address:
|
||||||
m_code << "let " << m_context.variable(_literal) << " := " << toCompactHexWithPrefix(type->literalValue(&_literal)) << "\n";
|
defineExpression(_literal) << toCompactHexWithPrefix(type->literalValue(&_literal)) << "\n";
|
||||||
break;
|
break;
|
||||||
case Type::Category::StringLiteral:
|
case Type::Category::StringLiteral:
|
||||||
solUnimplemented("");
|
solUnimplemented("");
|
||||||
@ -313,3 +370,8 @@ string IRGeneratorForStatements::expressionAsType(Expression const& _expression,
|
|||||||
else
|
else
|
||||||
return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")";
|
return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ostream& IRGeneratorForStatements::defineExpression(Expression const& _expression)
|
||||||
|
{
|
||||||
|
return m_code << "let " << m_context.variable(_expression) << " := ";
|
||||||
|
}
|
||||||
|
@ -46,6 +46,9 @@ public:
|
|||||||
|
|
||||||
bool visit(VariableDeclarationStatement const& _variableDeclaration) override;
|
bool visit(VariableDeclarationStatement const& _variableDeclaration) override;
|
||||||
bool visit(Assignment const& _assignment) 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;
|
bool visit(Return const& _return) override;
|
||||||
void endVisit(BinaryOperation const& _binOp) override;
|
void endVisit(BinaryOperation const& _binOp) override;
|
||||||
bool visit(FunctionCall const& _funCall) override;
|
bool visit(FunctionCall const& _funCall) override;
|
||||||
@ -57,6 +60,7 @@ private:
|
|||||||
/// @returns a Yul expression representing the current value of @a _expression,
|
/// @returns a Yul expression representing the current value of @a _expression,
|
||||||
/// converted to type @a _to if it does not yet have that type.
|
/// converted to type @a _to if it does not yet have that type.
|
||||||
std::string expressionAsType(Expression const& _expression, Type const& _to);
|
std::string expressionAsType(Expression const& _expression, Type const& _to);
|
||||||
|
std::ostream& defineExpression(Expression const& _expression);
|
||||||
|
|
||||||
std::ostringstream m_code;
|
std::ostringstream m_code;
|
||||||
IRGenerationContext& m_context;
|
IRGenerationContext& m_context;
|
||||||
|
@ -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}}}
|
||||||
|
@ -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}}}
|
||||||
|
40
test/libsolidity/semanticTests/viaYul/loops.sol
Normal file
40
test/libsolidity/semanticTests/viaYul/loops.sol
Normal file
@ -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
|
10
test/libsolidity/semanticTests/viaYul/return.sol
Normal file
10
test/libsolidity/semanticTests/viaYul/return.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure returns (uint x) {
|
||||||
|
return 7;
|
||||||
|
x = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f() -> 7
|
11
test/libsolidity/semanticTests/viaYul/return_and_convert.sol
Normal file
11
test/libsolidity/semanticTests/viaYul/return_and_convert.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure returns (uint) {
|
||||||
|
uint8 b;
|
||||||
|
assembly { b := 0xffff }
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f() -> 255
|
Loading…
Reference in New Issue
Block a user