mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fixed point type conversions.
This commit is contained in:
parent
1794e1c837
commit
70cbd5d8fb
@ -776,15 +776,11 @@ void CompilerUtils::convertType(
|
|||||||
solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\"");
|
solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\"");
|
||||||
|
|
||||||
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
|
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
|
||||||
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
|
bool chopSignBitsPending = false;
|
||||||
if (chopSignBitsPending)
|
if (_chopSignBits && targetTypeCategory == Type::Category::Integer)
|
||||||
{
|
chopSignBitsPending = dynamic_cast<IntegerType const&>(_targetType).isSigned();
|
||||||
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
|
else if (_chopSignBits && targetTypeCategory == Type::Category::FixedPoint)
|
||||||
chopSignBitsPending = targetIntegerType.isSigned();
|
chopSignBitsPending = dynamic_cast<FixedPointType const&>(_targetType).isSigned();
|
||||||
}
|
|
||||||
|
|
||||||
if (targetTypeCategory == Type::Category::FixedPoint)
|
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
|
||||||
|
|
||||||
switch (stackTypeCategory)
|
switch (stackTypeCategory)
|
||||||
{
|
{
|
||||||
@ -800,6 +796,14 @@ void CompilerUtils::convertType(
|
|||||||
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
|
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
|
||||||
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
|
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
|
||||||
}
|
}
|
||||||
|
else if (targetTypeCategory == Type::Category::FixedPoint)
|
||||||
|
{
|
||||||
|
// Conversion from bytes to fixed point type. No need to clean the high bit
|
||||||
|
// only to shift right because of opposite alignment.
|
||||||
|
FixedPointType const& targetFixedPointType = dynamic_cast<FixedPointType const&>(_targetType);
|
||||||
|
solAssert(targetFixedPointType.numBits() == typeOnStack.numBytes() * 8, "");
|
||||||
|
rightShiftNumberOnStack(256 - typeOnStack.numBytes() * 8);
|
||||||
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Address)
|
else if (targetTypeCategory == Type::Category::Address)
|
||||||
{
|
{
|
||||||
solAssert(typeOnStack.numBytes() * 8 == 160, "");
|
solAssert(typeOnStack.numBytes() * 8 == 160, "");
|
||||||
@ -835,10 +839,9 @@ void CompilerUtils::convertType(
|
|||||||
enumOverflowCheckPending = false;
|
enumOverflowCheckPending = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::Category::FixedPoint:
|
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
|
||||||
case Type::Category::Address:
|
case Type::Category::Address:
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
|
case Type::Category::FixedPoint:
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
if (targetTypeCategory == Type::Category::FixedBytes)
|
if (targetTypeCategory == Type::Category::FixedBytes)
|
||||||
@ -846,6 +849,7 @@ void CompilerUtils::convertType(
|
|||||||
solAssert(
|
solAssert(
|
||||||
stackTypeCategory == Type::Category::Address ||
|
stackTypeCategory == Type::Category::Address ||
|
||||||
stackTypeCategory == Type::Category::Integer ||
|
stackTypeCategory == Type::Category::Integer ||
|
||||||
|
stackTypeCategory == Type::Category::FixedPoint ||
|
||||||
stackTypeCategory == Type::Category::RationalNumber,
|
stackTypeCategory == Type::Category::RationalNumber,
|
||||||
"Invalid conversion to FixedBytesType requested."
|
"Invalid conversion to FixedBytesType requested."
|
||||||
);
|
);
|
||||||
@ -859,11 +863,14 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
else if (stackTypeCategory == Type::Category::Address)
|
else if (stackTypeCategory == Type::Category::Address)
|
||||||
solAssert(targetBytesType.numBytes() * 8 == 160, "");
|
solAssert(targetBytesType.numBytes() * 8 == 160, "");
|
||||||
|
else if (stackTypeCategory == Type::Category::FixedPoint)
|
||||||
|
solAssert(targetBytesType.numBytes() * 8 == dynamic_cast<FixedPointType const&>(_typeOnStack).numBits(), "");
|
||||||
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Enum)
|
else if (targetTypeCategory == Type::Category::Enum)
|
||||||
{
|
{
|
||||||
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
||||||
|
solAssert(stackTypeCategory != Type::Category::FixedPoint, "Invalid conversion to EnumType requested.");
|
||||||
solAssert(_typeOnStack.mobileType(), "");
|
solAssert(_typeOnStack.mobileType(), "");
|
||||||
// just clean
|
// just clean
|
||||||
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
||||||
@ -883,13 +890,41 @@ void CompilerUtils::convertType(
|
|||||||
);
|
);
|
||||||
//shift all integer bits onto the left side of the fixed type
|
//shift all integer bits onto the left side of the fixed type
|
||||||
FixedPointType const& targetFixedPointType = dynamic_cast<FixedPointType const&>(_targetType);
|
FixedPointType const& targetFixedPointType = dynamic_cast<FixedPointType const&>(_targetType);
|
||||||
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
unsigned fractionalDigitsOnStack = 0;
|
||||||
|
if (auto const* typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
||||||
|
{
|
||||||
if (targetFixedPointType.numBits() > typeOnStack->numBits())
|
if (targetFixedPointType.numBits() > typeOnStack->numBits())
|
||||||
cleanHigherOrderBits(*typeOnStack);
|
cleanHigherOrderBits(*typeOnStack);
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
}
|
||||||
|
else if (auto const* typeOnStack = dynamic_cast<FixedPointType const*>(&_typeOnStack))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
solUnimplementedAssert(typeOnStack->isSigned() == targetFixedPointType.isSigned(), "");
|
||||||
|
solUnimplementedAssert(typeOnStack->fractionalDigits() == targetFixedPointType.fractionalDigits(), "");
|
||||||
|
fractionalDigitsOnStack = typeOnStack->fractionalDigits();
|
||||||
|
}
|
||||||
|
else if (auto const* typeOnStack = dynamic_cast<RationalNumberType const*>(&_typeOnStack))
|
||||||
|
{
|
||||||
|
if (typeOnStack->isFractional())
|
||||||
|
fractionalDigitsOnStack = typeOnStack->fixedPointType()->fractionalDigits();
|
||||||
|
}
|
||||||
|
else if (auto const* typeOnStack = dynamic_cast<FixedBytesType const*>(&_typeOnStack))
|
||||||
|
solAssert(typeOnStack->numBytes() * 8 == targetFixedPointType.numBits(), "");
|
||||||
|
else
|
||||||
|
solAssert(false, "");
|
||||||
|
if (fractionalDigitsOnStack < targetFixedPointType.fractionalDigits())
|
||||||
|
m_context <<
|
||||||
|
pow(u256(10), targetFixedPointType.fractionalDigits() - fractionalDigitsOnStack) <<
|
||||||
|
Instruction::MUL;
|
||||||
|
else if (fractionalDigitsOnStack > targetFixedPointType.fractionalDigits())
|
||||||
|
m_context <<
|
||||||
|
pow(u256(10), fractionalDigitsOnStack - targetFixedPointType.fractionalDigits()) <<
|
||||||
|
// TODO needs to use SDIV
|
||||||
|
Instruction::DIV;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
solUnimplementedAssert(stackTypeCategory == Type::Category::FixedPoint, "");
|
||||||
solAssert(
|
solAssert(
|
||||||
targetTypeCategory == Type::Category::Integer ||
|
targetTypeCategory == Type::Category::Integer ||
|
||||||
targetTypeCategory == Type::Category::Contract ||
|
targetTypeCategory == Type::Category::Contract ||
|
||||||
@ -904,7 +939,7 @@ void CompilerUtils::convertType(
|
|||||||
RationalNumberType const& constType = dynamic_cast<RationalNumberType const&>(_typeOnStack);
|
RationalNumberType const& constType = dynamic_cast<RationalNumberType const&>(_typeOnStack);
|
||||||
// We know that the stack is clean, we only have to clean for a narrowing conversion
|
// We know that the stack is clean, we only have to clean for a narrowing conversion
|
||||||
// where cleanup is forced.
|
// where cleanup is forced.
|
||||||
solUnimplementedAssert(!constType.isFractional(), "Not yet implemented - FixedPointType.");
|
solUnimplementedAssert(!constType.isFractional(), "Not yet implemented - rational to integer conversion.");
|
||||||
if (targetType.numBits() < constType.integerType()->numBits() && _cleanupNeeded)
|
if (targetType.numBits() < constType.integerType()->numBits() && _cleanupNeeded)
|
||||||
cleanHigherOrderBits(targetType);
|
cleanHigherOrderBits(targetType);
|
||||||
}
|
}
|
||||||
|
@ -3266,13 +3266,17 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
|
case Type::Category::FixedPoint:
|
||||||
{
|
{
|
||||||
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&_from))
|
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&_from))
|
||||||
solUnimplementedAssert(!rational->isFractional(), "Not yet implemented - FixedPointType.");
|
if (rational->isFractional())
|
||||||
|
solAssert(toCategory == Type::Category::FixedPoint, "");
|
||||||
if (toCategory == Type::Category::FixedBytes)
|
if (toCategory == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
fromCategory == Type::Category::Integer || fromCategory == Type::Category::RationalNumber,
|
fromCategory == Type::Category::Integer ||
|
||||||
|
fromCategory == Type::Category::FixedPoint ||
|
||||||
|
fromCategory == Type::Category::RationalNumber,
|
||||||
"Invalid conversion to FixedBytesType requested."
|
"Invalid conversion to FixedBytesType requested."
|
||||||
);
|
);
|
||||||
FixedBytesType const& toBytesType = dynamic_cast<FixedBytesType const&>(_to);
|
FixedBytesType const& toBytesType = dynamic_cast<FixedBytesType const&>(_to);
|
||||||
@ -3284,6 +3288,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
}
|
}
|
||||||
else if (toCategory == Type::Category::Enum)
|
else if (toCategory == Type::Category::Enum)
|
||||||
{
|
{
|
||||||
|
solAssert(fromCategory != Type::Category::FixedPoint, "");
|
||||||
solAssert(_from.mobileType(), "");
|
solAssert(_from.mobileType(), "");
|
||||||
body =
|
body =
|
||||||
Whiskers("converted := <cleanEnum>(<cleanInt>(value))")
|
Whiskers("converted := <cleanEnum>(<cleanInt>(value))")
|
||||||
@ -3293,7 +3298,41 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
else if (toCategory == Type::Category::FixedPoint)
|
else if (toCategory == Type::Category::FixedPoint)
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
{
|
||||||
|
FixedPointType const& toFixedType = dynamic_cast<FixedPointType const&>(_to);
|
||||||
|
int digitDifference = static_cast<int>(toFixedType.fractionalDigits());
|
||||||
|
bool isSigned = false;
|
||||||
|
if (auto const* fromIntegerType = dynamic_cast<IntegerType const*>(&_from))
|
||||||
|
{
|
||||||
|
solAssert(
|
||||||
|
fromIntegerType->maxValue() <= toFixedType.maxIntegerValue() &&
|
||||||
|
fromIntegerType->minValue() >= toFixedType.minIntegerValue(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
isSigned = fromIntegerType->isSigned();
|
||||||
|
}
|
||||||
|
else if (auto const* fromFixedType = dynamic_cast<FixedPointType const*>(&_from))
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(fromFixedType->isSigned() == toFixedType.isSigned(), "");
|
||||||
|
isSigned = fromFixedType->isSigned();
|
||||||
|
digitDifference -= static_cast<int>(fromFixedType->fractionalDigits());
|
||||||
|
}
|
||||||
|
else if (auto const* fromRationalType = dynamic_cast<RationalNumberType const*>(&_from))
|
||||||
|
{
|
||||||
|
if (fromRationalType->isFractional())
|
||||||
|
digitDifference -= static_cast<int>(fromRationalType->fixedPointType()->fractionalDigits());
|
||||||
|
isSigned = fromRationalType->isNegative();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solAssert(false, "");
|
||||||
|
// TODO maybe target cleanup can be avoided in some cases.
|
||||||
|
body = Whiskers{"converted := <cleanupTarget>(<operator>(<cleanupSource>(value), <factor>))"}
|
||||||
|
("cleanupSource", cleanupFunction(_from))
|
||||||
|
("operator", digitDifference >= 0 ? "mul" : isSigned ? "sdiv" : "div")
|
||||||
|
("factor", "1" + string(static_cast<unsigned>(abs(digitDifference)), '0'))
|
||||||
|
("cleanupTarget", cleanupFunction(toFixedType))
|
||||||
|
.render();
|
||||||
|
}
|
||||||
else if (toCategory == Type::Category::Address)
|
else if (toCategory == Type::Category::Address)
|
||||||
body =
|
body =
|
||||||
Whiskers("converted := <convert>(value)")
|
Whiskers("converted := <convert>(value)")
|
||||||
@ -3339,9 +3378,6 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
.render();
|
.render();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::FixedPoint:
|
|
||||||
solUnimplemented("Fixed point types not implemented.");
|
|
||||||
break;
|
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
{
|
{
|
||||||
solAssert(toCategory == Type::Category::Struct, "");
|
solAssert(toCategory == Type::Category::Struct, "");
|
||||||
@ -3390,6 +3426,18 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
("shift", shiftRightFunction(256 - from.numBytes() * 8))
|
("shift", shiftRightFunction(256 - from.numBytes() * 8))
|
||||||
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
|
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
|
||||||
.render();
|
.render();
|
||||||
|
else if (toCategory == Type::Category::FixedPoint)
|
||||||
|
{
|
||||||
|
auto const& toFixedPoint = dynamic_cast<FixedPointType const&>(_to);
|
||||||
|
IntegerType integerType(
|
||||||
|
toFixedPoint.numBits(),
|
||||||
|
toFixedPoint.isSigned() ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned
|
||||||
|
);
|
||||||
|
body =
|
||||||
|
Whiskers("converted := <convert>(value)")
|
||||||
|
("convert", conversionFunction(_from, integerType))
|
||||||
|
.render();
|
||||||
|
}
|
||||||
else if (toCategory == Type::Category::Address)
|
else if (toCategory == Type::Category::Address)
|
||||||
body =
|
body =
|
||||||
Whiskers("converted := <convert>(value)")
|
Whiskers("converted := <convert>(value)")
|
||||||
@ -3734,15 +3782,15 @@ string YulUtilFunctions::cleanupFunction(Type const& _type)
|
|||||||
templ("body", "cleaned := and(value, " + toCompactHexWithPrefix((u256(1) << type.numBits()) - 1) + ")");
|
templ("body", "cleaned := and(value, " + toCompactHexWithPrefix((u256(1) << type.numBits()) - 1) + ")");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::Category::FixedPoint:
|
||||||
|
templ("body", "cleaned := " + cleanupFunction(*dynamic_cast<FixedPointType const&>(_type).asIntegerType()) + "(value)");
|
||||||
|
break;
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
templ("body", "cleaned := value");
|
templ("body", "cleaned := value");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
templ("body", "cleaned := iszero(iszero(value))");
|
templ("body", "cleaned := iszero(iszero(value))");
|
||||||
break;
|
break;
|
||||||
case Type::Category::FixedPoint:
|
|
||||||
solUnimplemented("Fixed point types not implemented.");
|
|
||||||
break;
|
|
||||||
case Type::Category::Function:
|
case Type::Category::Function:
|
||||||
switch (dynamic_cast<FunctionType const&>(_type).kind())
|
switch (dynamic_cast<FunctionType const&>(_type).kind())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user