[Sol -> Yul] Implement unary -, +

This commit is contained in:
Mathias Baumann 2019-05-16 18:59:29 +02:00
parent 7dbcb80523
commit 86000fdcce
4 changed files with 69 additions and 6 deletions

View File

@ -1088,6 +1088,28 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type)
}); });
} }
string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type)
{
IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
solAssert(type.isSigned(), "Expected signed type!");
string const functionName = "negate_" + _type.identifier();
u256 const minintval = 0 - (u256(1) << (type.numBits() - 1)) + 1;
return m_functionCollector->createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>(_value) -> ret {
if slt(_value, <minval>) { revert(0,0) }
ret := sub(0, _value)
}
)")
("functionName", functionName)
("minval", toCompactHexWithPrefix(minintval))
.render();
});
}
string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to) string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to)
{ {
string functionName = string functionName =

View File

@ -179,6 +179,8 @@ public:
std::string incrementCheckedFunction(Type const& _type); std::string incrementCheckedFunction(Type const& _type);
std::string decrementCheckedFunction(Type const& _type); std::string decrementCheckedFunction(Type const& _type);
std::string negateNumberCheckedFunction(Type const& _type);
private: private:
/// Special case of conversionFunction - handles everything that does not /// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value. /// use exactly one variable to hold the value.

View File

@ -265,23 +265,39 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
) << ) <<
"(" << "(" <<
originalValue << originalValue <<
")\n" << ")\n";
m_currentLValue->storeValue(modifiedValue, resultType); m_code << m_currentLValue->storeValue(modifiedValue, resultType);
m_currentLValue.reset();
defineExpression(_unaryOperation) << defineExpression(_unaryOperation) <<
(_unaryOperation.isPrefixOperation() ? modifiedValue : originalValue) << (_unaryOperation.isPrefixOperation() ? modifiedValue : originalValue) <<
"\n"; "\n";
m_code << m_currentLValue->storeValue(modifiedValue, resultType);
m_currentLValue.reset();
} }
else if (op == Token::BitNot) else if (op == Token::BitNot)
appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression()); appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression());
else if (op == Token::Add)
// According to SyntaxChecker...
solAssert(false, "Use of unary + is disallowed.");
else if (op == Token::Sub)
{
IntegerType const& intType = *dynamic_cast<IntegerType const*>(&resultType);
defineExpression(_unaryOperation) <<
m_utils.negateNumberCheckedFunction(intType) <<
"(" <<
m_context.variable(_unaryOperation.subExpression()) <<
")\n";
}
else else
solUnimplementedAssert(false, "Unary operator not yet implemented"); solUnimplementedAssert(false, "Unary operator not yet implemented");
} }
else if (resultType.category() == Type::Category::Bool) else if (resultType.category() == Type::Category::Bool)
{ {
solAssert(
_unaryOperation.getOperator() != Token::BitNot,
"Bitwise Negation can't be done on bool!"
);
appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression()); appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression());
} }
else else

View File

@ -69,6 +69,18 @@ contract C {
ret := a ret := a
} }
} }
function negate(int256 a) public pure returns (int256)
{
return -a;
}
function negate_s8(int8 a) public pure returns (int8)
{
return -a;
}
function negate_s16(int16 a) public pure returns (int16)
{
return -a;
}
} }
// ==== // ====
// compileViaYul: true // compileViaYul: true
@ -111,3 +123,14 @@ contract C {
// bitnot(int256): -100 -> 99 // bitnot(int256): -100 -> 99
// bitnot_u8(uint8): 100 -> 155 // bitnot_u8(uint8): 100 -> 155
// bitnot_s8() -> 99 // bitnot_s8() -> 99
// negate(int256): -57896044618658097711785492504343953926634992332820282019728792003956564819968 -> FAILURE
// negate(int256): -57896044618658097711785492504343953926634992332820282019728792003956564819967 -> 57896044618658097711785492504343953926634992332820282019728792003956564819967
// negate(int256): 0 -> 0
// negate(int256): 1 -> -1
// negate(int256): -1 -> 1
// negate_s8(int8): -128 -> FAILURE
// negate_s8(int8): -138 -> FAILURE
// negate_s8(int8): -127 -> 127
// negate_s8(int8): 127 -> -127
// negate_s16(int16): -32768 -> FAILURE
// negate_s16(int16): -32767 -> 32767