mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SolYul] Division.
This commit is contained in:
parent
b836079006
commit
fbf189151d
@ -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 YulUtilFunctions::overflowCheckedUIntSubFunction()
|
||||||
{
|
{
|
||||||
string functionName = "checked_sub_uint";
|
string functionName = "checked_sub_uint";
|
||||||
|
@ -36,6 +36,7 @@ namespace solidity
|
|||||||
class Type;
|
class Type;
|
||||||
class ArrayType;
|
class ArrayType;
|
||||||
class MappingType;
|
class MappingType;
|
||||||
|
class IntegerType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that can generate various useful Yul functions.
|
* Component that can generate various useful Yul functions.
|
||||||
@ -88,6 +89,11 @@ public:
|
|||||||
|
|
||||||
std::string overflowCheckedUIntMulFunction(size_t _bits);
|
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.
|
/// @returns computes the difference between two values.
|
||||||
/// Assumes the input to be in range for the type.
|
/// Assumes the input to be in range for the type.
|
||||||
std::string overflowCheckedUIntSubFunction();
|
std::string overflowCheckedUIntSubFunction();
|
||||||
|
@ -391,7 +391,6 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
|||||||
{
|
{
|
||||||
string left = expressionAsType(_binOp.leftExpression(), *commonType);
|
string left = expressionAsType(_binOp.leftExpression(), *commonType);
|
||||||
string right = expressionAsType(_binOp.rightExpression(), *commonType);
|
string right = expressionAsType(_binOp.rightExpression(), *commonType);
|
||||||
|
|
||||||
defineExpression(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right);
|
defineExpression(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1097,16 +1096,20 @@ string IRGeneratorForStatements::binaryOperation(
|
|||||||
{
|
{
|
||||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
|
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(!type->isSigned(), "");
|
|
||||||
string fun;
|
string fun;
|
||||||
if (_operator == Token::Add)
|
// TODO: Only division is implemented for signed integers for now.
|
||||||
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
|
if (!type->isSigned())
|
||||||
else if (_operator == Token::Sub)
|
{
|
||||||
fun = m_utils.overflowCheckedUIntSubFunction();
|
if (_operator == Token::Add)
|
||||||
else if (_operator == Token::Mul)
|
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
|
||||||
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
|
else if (_operator == Token::Sub)
|
||||||
else
|
fun = m_utils.overflowCheckedUIntSubFunction();
|
||||||
solUnimplementedAssert(false, "");
|
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";
|
return fun + "(" + _left + ", " + _right + ")\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
contract C {
|
||||||
|
function f(uint a, uint b) public pure returns (uint x) {
|
||||||
|
x = a / b;
|
||||||
|
}
|
||||||
|
function g(int8 a, int8 b) public pure returns (int8 x) {
|
||||||
|
x = a / b;
|
||||||
|
}
|
||||||
|
function h(uint256 a, uint256 b) public pure returns (uint256 x) {
|
||||||
|
x = a / b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f(uint256,uint256): 10, 3 -> 3
|
||||||
|
// f(uint256,uint256): 1, 0 -> FAILURE
|
||||||
|
// f(uint256,uint256): 0, 0 -> FAILURE
|
||||||
|
// f(uint256,uint256): 0, 1 -> 0
|
||||||
|
// g(int8,int8): -10, 3 -> -3
|
||||||
|
// g(int8,int8): -10, -3 -> 3
|
||||||
|
// g(int8,int8): -10, 0 -> FAILURE
|
||||||
|
// g(int8,int8): -128, 1 -> -128
|
||||||
|
// g(int8,int8): -128, -2 -> 64
|
||||||
|
// g(int8,int8): -128, 2 -> -64
|
||||||
|
// g(int8,int8): -128, -1 -> FAILURE
|
||||||
|
// g(int8,int8): -127, -1 -> 127
|
||||||
|
// h(uint256,uint256): 0x8000000000000000000000000000000000000000000000000000000000000000, -1 -> 0
|
Loading…
Reference in New Issue
Block a user