From 7ad319687d3465c5032bf691f5aa0b4700c44491 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 13:06:01 +0200 Subject: [PATCH] Sol->Yul: Add cleanup to operations. --- libsolidity/codegen/YulUtilFunctions.cpp | 51 +++++++++++++------ .../codegen/ir/IRGeneratorForStatements.cpp | 13 +++-- .../codegen/ir/IRGeneratorForStatements.h | 3 +- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 75d297b34..481fbc479 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -393,6 +393,8 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> sum { + x := (x) + y := (y) // overflow, if x >= 0 and y > (maxValue - x) if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { revert(0, 0) } @@ -409,6 +411,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -421,6 +424,8 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) // Multiplication by zero could be treated separately and directly return zero. Whiskers(R"( function (x, y) -> product { + x := (x) + y := (y) // overflow, if x > 0, y > 0 and x > (maxValue / y) if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { revert(0, 0) } @@ -441,6 +446,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -452,6 +458,8 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } // overflow for minVal / -1 @@ -466,6 +474,7 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) ("functionName", functionName) ("signed", _type.isSigned()) ("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -477,12 +486,15 @@ string YulUtilFunctions::checkedIntModFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } r := smod(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -494,6 +506,8 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> diff { + x := (x) + y := (y) // underflow, if y >= 0 and x < (minValue + y) if and(iszero(slt(y, 0)), slt(x, add(, y))) { revert(0, 0) } @@ -509,6 +523,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -1938,14 +1953,16 @@ std::string YulUtilFunctions::decrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := sub(value, 1) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - ("lt", type.isSigned() ? "slt" : "lt") - .render(); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("lt", type.isSigned() ? "slt" : "lt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1966,14 +1983,16 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := add(value, 1) } )") - ("functionName", functionName) - ("maxval", toCompactHexWithPrefix(maxintval)) - ("gt", type.isSigned() ? "sgt" : "gt") - .render(); + ("functionName", functionName) + ("maxval", toCompactHexWithPrefix(maxintval)) + ("gt", type.isSigned() ? "sgt" : "gt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1988,15 +2007,17 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type) return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( - function (_value) -> ret { - if slt(_value, ) { revert(0,0) } - ret := sub(0, _value) + function (value) -> ret { + value := (value) + if slt(value, ) { revert(0,0) } + ret := sub(0, value) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - .render(); - }); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("cleanupFunction", cleanupFunction(_type)) + .render(); + }); } string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f8c8b2956..f795e0e98 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -496,9 +496,9 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) isSigned = type->isSigned(); string args = - expressionAsType(_binOp.leftExpression(), *commonType) + + expressionAsType(_binOp.leftExpression(), *commonType, true) + ", " + - expressionAsType(_binOp.rightExpression(), *commonType); + expressionAsType(_binOp.rightExpression(), *commonType, true); string expr; if (op == Token::Equal) @@ -1811,11 +1811,16 @@ IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const } } -std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) +std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup) { IRVariable from(_expression); if (from.type() == _to) - return from.commaSeparatedList(); + { + if (_forceCleanup) + return m_utils.cleanupFunction(_to) + "(" + from.commaSeparatedList() + ")"; + else + return from.commaSeparatedList(); + } else return m_utils.conversionFunction(from.type(), _to) + "(" + from.commaSeparatedList() + ")"; } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b8fafd8b6..e4282c2b3 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -112,7 +112,8 @@ 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); + /// If @a _forceCleanup is set to true, it also cleans the value, in case it already has type @a _to. + std::string expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup = false); /// @returns an output stream that can be used to define @a _var using a function call or /// single stack slot expression.