[SolYul] Division.

This commit is contained in:
chriseth
2019-05-27 17:53:46 +02:00
parent b836079006
commit fbf189151d
4 changed files with 73 additions and 10 deletions
+27
View File
@@ -374,6 +374,33 @@ string YulUtilFunctions::overflowCheckedUIntMulFunction(size_t _bits)
});
}
string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type)
{
unsigned bits = _type.numBits();
solAssert(0 < bits && bits <= 256 && bits % 8 == 0, "");
string functionName = "checked_div_" + _type.identifier();
return m_functionCollector->createFunction(functionName, [&]() {
return
Whiskers(R"(
function <functionName>(x, y) -> r {
if iszero(y) { revert(0, 0) }
<?signed>
// x / -1 == x
if and(
eq(x, <minVal>),
eq(y, sub(0, 1))
) { revert(0, 0) }
</signed>
r := <?signed>s</signed>div(x, y)
}
)")
("functionName", functionName)
("signed", _type.isSigned())
("minVal", (0 - (u256(1) << (bits - 1))).str())
.render();
});
}
string YulUtilFunctions::overflowCheckedUIntSubFunction()
{
string functionName = "checked_sub_uint";
+6
View File
@@ -36,6 +36,7 @@ namespace solidity
class Type;
class ArrayType;
class MappingType;
class IntegerType;
/**
* Component that can generate various useful Yul functions.
@@ -88,6 +89,11 @@ public:
std::string overflowCheckedUIntMulFunction(size_t _bits);
/// @returns name of function to perform division on integers.
/// Checks for division by zero and the special case of
/// signed division of the smallest number by -1.
std::string overflowCheckedIntDivFunction(IntegerType const& _type);
/// @returns computes the difference between two values.
/// Assumes the input to be in range for the type.
std::string overflowCheckedUIntSubFunction();
@@ -391,7 +391,6 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{
string left = expressionAsType(_binOp.leftExpression(), *commonType);
string right = expressionAsType(_binOp.rightExpression(), *commonType);
defineExpression(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right);
}
return false;
@@ -1097,16 +1096,20 @@ string IRGeneratorForStatements::binaryOperation(
{
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
{
solUnimplementedAssert(!type->isSigned(), "");
string fun;
if (_operator == Token::Add)
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_operator == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_operator == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
else
solUnimplementedAssert(false, "");
// TODO: Only division is implemented for signed integers for now.
if (!type->isSigned())
{
if (_operator == Token::Add)
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_operator == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_operator == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
}
if (_operator == Token::Div)
fun = m_utils.overflowCheckedIntDivFunction(*type);
solUnimplementedAssert(!fun.empty(), "");
return fun + "(" + _left + ", " + _right + ")\n";
}
else