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
3fe4b0b2c3
commit
d1aa217936
@ -776,15 +776,11 @@ void CompilerUtils::convertType(
|
||||
solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\"");
|
||||
|
||||
bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum);
|
||||
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
|
||||
if (chopSignBitsPending)
|
||||
{
|
||||
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
|
||||
chopSignBitsPending = targetIntegerType.isSigned();
|
||||
}
|
||||
|
||||
if (targetTypeCategory == Type::Category::FixedPoint)
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
bool chopSignBitsPending = false;
|
||||
if (_chopSignBits && targetTypeCategory == Type::Category::Integer)
|
||||
chopSignBitsPending = dynamic_cast<IntegerType const&>(_targetType).isSigned();
|
||||
else if (_chopSignBits && targetTypeCategory == Type::Category::FixedPoint)
|
||||
chopSignBitsPending = dynamic_cast<FixedPointType const&>(_targetType).isSigned();
|
||||
|
||||
switch (stackTypeCategory)
|
||||
{
|
||||
@ -800,6 +796,14 @@ void CompilerUtils::convertType(
|
||||
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
|
||||
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)
|
||||
{
|
||||
solAssert(typeOnStack.numBytes() * 8 == 160, "");
|
||||
@ -835,10 +839,9 @@ void CompilerUtils::convertType(
|
||||
enumOverflowCheckPending = false;
|
||||
}
|
||||
break;
|
||||
case Type::Category::FixedPoint:
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
case Type::Category::Address:
|
||||
case Type::Category::Integer:
|
||||
case Type::Category::FixedPoint:
|
||||
case Type::Category::Contract:
|
||||
case Type::Category::RationalNumber:
|
||||
if (targetTypeCategory == Type::Category::FixedBytes)
|
||||
@ -846,6 +849,7 @@ void CompilerUtils::convertType(
|
||||
solAssert(
|
||||
stackTypeCategory == Type::Category::Address ||
|
||||
stackTypeCategory == Type::Category::Integer ||
|
||||
stackTypeCategory == Type::Category::FixedPoint ||
|
||||
stackTypeCategory == Type::Category::RationalNumber,
|
||||
"Invalid conversion to FixedBytesType requested."
|
||||
);
|
||||
@ -859,11 +863,14 @@ void CompilerUtils::convertType(
|
||||
}
|
||||
else if (stackTypeCategory == Type::Category::Address)
|
||||
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);
|
||||
}
|
||||
else if (targetTypeCategory == Type::Category::Enum)
|
||||
{
|
||||
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
||||
solAssert(stackTypeCategory != Type::Category::FixedPoint, "Invalid conversion to EnumType requested.");
|
||||
solAssert(_typeOnStack.mobileType(), "");
|
||||
// just clean
|
||||
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
||||
@ -881,12 +888,51 @@ void CompilerUtils::convertType(
|
||||
stackTypeCategory == Type::Category::FixedPoint,
|
||||
"Invalid conversion to FixedMxNType requested."
|
||||
);
|
||||
//shift all integer bits onto the left side of the fixed type
|
||||
|
||||
FixedPointType const& targetFixedPointType = dynamic_cast<FixedPointType const&>(_targetType);
|
||||
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
||||
if (targetFixedPointType.numBits() > typeOnStack->numBits())
|
||||
cleanHigherOrderBits(*typeOnStack);
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
int digitDifference = static_cast<int>(targetFixedPointType.fractionalDigits());
|
||||
bool isSigned = false;
|
||||
if (auto const* typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
||||
{
|
||||
cleanHigherOrderBits(*typeOnStack);
|
||||
isSigned = typeOnStack->isSigned();
|
||||
}
|
||||
else if (auto const* typeOnStack = dynamic_cast<FixedPointType const*>(&_typeOnStack))
|
||||
{
|
||||
isSigned = typeOnStack->isSigned();
|
||||
digitDifference -= static_cast<int>(typeOnStack->fractionalDigits());
|
||||
if (typeOnStack->isSigned() != targetFixedPointType.isSigned())
|
||||
solAssert(digitDifference >= 0, "");
|
||||
if (digitDifference < 0 || typeOnStack->numBits() < targetFixedPointType.numBits())
|
||||
cleanHigherOrderBits(*typeOnStack->asIntegerType());
|
||||
}
|
||||
else if (auto const* typeOnStack = dynamic_cast<RationalNumberType const*>(&_typeOnStack))
|
||||
{
|
||||
if (typeOnStack->isFractional())
|
||||
digitDifference -= static_cast<int>(typeOnStack->closestFixedPointType()->fractionalDigits());
|
||||
isSigned = typeOnStack->isNegative();
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
if (digitDifference > 0)
|
||||
m_context << pow(u256(10), static_cast<unsigned>(digitDifference)) << Instruction::MUL;
|
||||
else if (digitDifference < 0)
|
||||
m_context <<
|
||||
pow(u256(10), static_cast<unsigned>(-digitDifference)) <<
|
||||
Instruction::SWAP1 <<
|
||||
(isSigned ? Instruction::SDIV : Instruction::DIV);
|
||||
|
||||
if (_cleanupNeeded)
|
||||
cleanHigherOrderBits(*targetFixedPointType.asIntegerType());
|
||||
if (chopSignBitsPending)
|
||||
{
|
||||
if (targetFixedPointType.numBits() < 256)
|
||||
m_context
|
||||
<< ((u256(1) << targetFixedPointType.numBits()) - 1)
|
||||
<< Instruction::AND;
|
||||
chopSignBitsPending = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -897,35 +943,50 @@ void CompilerUtils::convertType(
|
||||
""
|
||||
);
|
||||
IntegerType addressType(160);
|
||||
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
|
||||
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
|
||||
IntegerType const& targetType =
|
||||
targetTypeCategory == Type::Category::Integer ?
|
||||
dynamic_cast<IntegerType const&>(_targetType) :
|
||||
addressType;
|
||||
if (stackTypeCategory == Type::Category::RationalNumber)
|
||||
{
|
||||
RationalNumberType const& constType = dynamic_cast<RationalNumberType const&>(_typeOnStack);
|
||||
// We know that the stack is clean, we only have to clean for a narrowing conversion
|
||||
// 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)
|
||||
cleanHigherOrderBits(targetType);
|
||||
}
|
||||
else if (stackTypeCategory == Type::Category::FixedPoint)
|
||||
{
|
||||
FixedPointType const& typeOnStack = dynamic_cast<FixedPointType const&>(_typeOnStack);
|
||||
solAssert(typeOnStack.isSigned() == targetType.isSigned(), "");
|
||||
cleanHigherOrderBits(*typeOnStack.asIntegerType());
|
||||
m_context <<
|
||||
pow(u256(10), typeOnStack.fractionalDigits()) <<
|
||||
(typeOnStack.isSigned() ? Instruction::SDIV : Instruction::DIV);
|
||||
if (_cleanupNeeded)
|
||||
cleanHigherOrderBits(targetType);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntegerType const& typeOnStack = stackTypeCategory == Type::Category::Integer
|
||||
? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
|
||||
IntegerType const& typeOnStack =
|
||||
stackTypeCategory == Type::Category::Integer ?
|
||||
dynamic_cast<IntegerType const&>(_typeOnStack) :
|
||||
addressType;
|
||||
// Widening: clean up according to source type width
|
||||
// Non-widening and force: clean up according to target type bits
|
||||
if (targetType.numBits() > typeOnStack.numBits())
|
||||
cleanHigherOrderBits(typeOnStack);
|
||||
else if (_cleanupNeeded)
|
||||
cleanHigherOrderBits(targetType);
|
||||
if (chopSignBitsPending)
|
||||
{
|
||||
if (targetType.numBits() < 256)
|
||||
m_context
|
||||
<< ((u256(1) << targetType.numBits()) - 1)
|
||||
<< Instruction::AND;
|
||||
chopSignBitsPending = false;
|
||||
}
|
||||
}
|
||||
if (chopSignBitsPending)
|
||||
{
|
||||
if (targetType.numBits() < 256)
|
||||
m_context
|
||||
<< ((u256(1) << targetType.numBits()) - 1)
|
||||
<< Instruction::AND;
|
||||
chopSignBitsPending = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1553,8 +1614,13 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
||||
cleanupNeeded = false;
|
||||
}
|
||||
else if (IntegerType const* intType = dynamic_cast<IntegerType const*>(&_type))
|
||||
{
|
||||
if (!intType->isSigned())
|
||||
cleanupNeeded = false;
|
||||
}
|
||||
else if (auto const* fixedPointType = dynamic_cast<FixedPointType const*>(&_type))
|
||||
if (!fixedPointType->isSigned())
|
||||
cleanupNeeded = false;
|
||||
}
|
||||
if (_fromCalldata)
|
||||
convertType(_type, _type, cleanupNeeded, false, true);
|
||||
|
@ -2229,6 +2229,8 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const&
|
||||
bool isSigned = false;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(&_type))
|
||||
isSigned = type->isSigned();
|
||||
else if (auto type = dynamic_cast<FixedPointType const*>(&_type))
|
||||
isSigned = type->isSigned();
|
||||
|
||||
switch (_operator)
|
||||
{
|
||||
|
@ -222,18 +222,18 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
m_context
|
||||
<< Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1
|
||||
<< u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV;
|
||||
if (m_dataType->category() == Type::Category::FixedPoint)
|
||||
// implementation should be very similar to the integer case.
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
if (m_dataType->category() == Type::Category::FixedBytes)
|
||||
{
|
||||
CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * m_dataType->storageBytes());
|
||||
cleaned = true;
|
||||
}
|
||||
else if (
|
||||
m_dataType->category() == Type::Category::Integer &&
|
||||
dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
|
||||
)
|
||||
else if ((
|
||||
m_dataType->category() == Type::Category::Integer &&
|
||||
dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
|
||||
) || (
|
||||
m_dataType->category() == Type::Category::FixedPoint &&
|
||||
dynamic_cast<FixedPointType const&>(*m_dataType).isSigned()
|
||||
))
|
||||
{
|
||||
m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND;
|
||||
cleaned = true;
|
||||
@ -332,7 +332,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
// remove the higher order bits
|
||||
utils.convertType(_sourceType, *m_dataType, true, true);
|
||||
}
|
||||
m_context << Instruction::MUL << Instruction::OR;
|
||||
m_context << Instruction::MUL << Instruction::OR;
|
||||
// stack: value storage_ref updated_value
|
||||
m_context << Instruction::SWAP1 << Instruction::SSTORE;
|
||||
if (_move)
|
||||
|
@ -292,7 +292,7 @@ string YulUtilFunctions::leftAlignFunction(Type const& _type)
|
||||
templ("body", "aligned := " + leftAlignFunction(IntegerType(8)) + "(value)");
|
||||
break;
|
||||
case Type::Category::FixedPoint:
|
||||
solUnimplemented("Fixed point types not implemented.");
|
||||
templ("body", "aligned := " + leftAlignFunction(*dynamic_cast<FixedPointType const&>(_type).asIntegerType()) + "(value)");
|
||||
break;
|
||||
case Type::Category::Array:
|
||||
case Type::Category::Struct:
|
||||
@ -445,7 +445,7 @@ string YulUtilFunctions::shiftRightSignedFunctionDynamic()
|
||||
|
||||
string YulUtilFunctions::typedShiftLeftFunction(Type const& _type, Type const& _amountType)
|
||||
{
|
||||
solUnimplementedAssert(_type.category() != Type::Category::FixedPoint, "Not yet implemented - FixedPointType.");
|
||||
solAssert(_type.category() != Type::Category::FixedPoint, "No operators for fixed point types.");
|
||||
solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, "");
|
||||
solAssert(_amountType.category() == Type::Category::Integer, "");
|
||||
solAssert(!dynamic_cast<IntegerType const&>(_amountType).isSigned(), "");
|
||||
@ -468,7 +468,7 @@ string YulUtilFunctions::typedShiftLeftFunction(Type const& _type, Type const& _
|
||||
|
||||
string YulUtilFunctions::typedShiftRightFunction(Type const& _type, Type const& _amountType)
|
||||
{
|
||||
solUnimplementedAssert(_type.category() != Type::Category::FixedPoint, "Not yet implemented - FixedPointType.");
|
||||
solAssert(_type.category() != Type::Category::FixedPoint, "No operators for fixed point types.");
|
||||
solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, "");
|
||||
solAssert(_amountType.category() == Type::Category::Integer, "");
|
||||
solAssert(!dynamic_cast<IntegerType const&>(_amountType).isSigned(), "");
|
||||
@ -492,6 +492,22 @@ string YulUtilFunctions::typedShiftRightFunction(Type const& _type, Type const&
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::fixedPointShiftFunction(int _digits, bool _signed)
|
||||
{
|
||||
string digitsStr = _digits < 0 ? ("n_" + to_string(-_digits)) : to_string(_digits);
|
||||
string const functionName = "fixed_point_shift_" + digitsStr + (_signed ? "_signed" : "_unsigned");
|
||||
return m_functionCollector.createFunction(functionName, [&](vector<string>& _args, vector<string>& _ret) {
|
||||
_args = {"value"};
|
||||
_ret = {"result"};
|
||||
return
|
||||
Whiskers("result := <op>(value, <factor>)")
|
||||
("op", _digits >= 0 ? "mul" : _signed ? "sdiv" : "div")
|
||||
("factor", ("1" + string(static_cast<unsigned>(abs(_digits)), '0')))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
string YulUtilFunctions::updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes)
|
||||
{
|
||||
solAssert(_numBytes <= 32, "");
|
||||
@ -3276,11 +3292,18 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
break;
|
||||
case Type::Category::Integer:
|
||||
case Type::Category::RationalNumber:
|
||||
case Type::Category::FixedPoint:
|
||||
{
|
||||
solAssert(_from.mobileType(), "");
|
||||
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&_from))
|
||||
{
|
||||
if (rational->isFractional())
|
||||
solAssert(toCategory == Type::Category::FixedPoint, "");
|
||||
solAssert(
|
||||
toCategory == Type::Category::FixedPoint &&
|
||||
rational->closestFixedPointType(),
|
||||
"");
|
||||
else
|
||||
solAssert(rational->mobileType(), "");
|
||||
}
|
||||
|
||||
if (toCategory == Type::Category::Address || toCategory == Type::Category::Contract)
|
||||
body =
|
||||
@ -3296,12 +3319,56 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
|
||||
if (auto const* toFixedBytes = dynamic_cast<FixedBytesType const*>(&_to))
|
||||
convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8);
|
||||
else if (dynamic_cast<FixedPointType const*>(&_to))
|
||||
solUnimplementedAssert(false, "");
|
||||
else if (dynamic_cast<IntegerType const*>(&_to))
|
||||
else if (auto const* toFixedPoint = dynamic_cast<FixedPointType const*>(&_to))
|
||||
{
|
||||
solUnimplementedAssert(fromCategory != Type::Category::FixedPoint, "");
|
||||
convert = identityFunction();
|
||||
int digitDifference = static_cast<int>(toFixedPoint->fractionalDigits());
|
||||
bool isSigned = false;
|
||||
if (auto const* fromIntegerType = dynamic_cast<IntegerType const*>(&_from))
|
||||
{
|
||||
solAssert(
|
||||
fromIntegerType->maxValue() <= toFixedPoint->maxIntegerValue() &&
|
||||
fromIntegerType->minValue() >= toFixedPoint->minIntegerValue(),
|
||||
""
|
||||
);
|
||||
isSigned = fromIntegerType->isSigned();
|
||||
}
|
||||
else if (auto const* fromFixedType = dynamic_cast<FixedPointType const*>(&_from))
|
||||
{
|
||||
isSigned = fromFixedType->isSigned();
|
||||
digitDifference -= static_cast<int>(fromFixedType->fractionalDigits());
|
||||
if (fromFixedType->isSigned() != toFixedPoint->isSigned())
|
||||
solAssert(digitDifference >= 0, "");
|
||||
}
|
||||
else if (auto const* fromRationalType = dynamic_cast<RationalNumberType const*>(&_from))
|
||||
{
|
||||
if (fromRationalType->isFractional())
|
||||
digitDifference -= static_cast<int>(
|
||||
fromRationalType->closestFixedPointType()->fractionalDigits()
|
||||
);
|
||||
isSigned = fromRationalType->isNegative();
|
||||
solAssert(
|
||||
fromRationalType->value() >= toFixedPoint->minValue() &&
|
||||
fromRationalType->value() <= toFixedPoint->maxValue(),
|
||||
""
|
||||
);
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
convert = fixedPointShiftFunction(digitDifference, isSigned);
|
||||
}
|
||||
else if (auto const* to = dynamic_cast<IntegerType const*>(&_to))
|
||||
{
|
||||
if (fromCategory == Type::Category::FixedPoint)
|
||||
{
|
||||
auto const& fixedFrom = dynamic_cast<FixedPointType const&>(_from);
|
||||
solAssert(fixedFrom.isSigned() == to->isSigned(), "" );
|
||||
convert = fixedPointShiftFunction(
|
||||
static_cast<int>(fixedFrom.fractionalDigits()),
|
||||
to->isSigned()
|
||||
);
|
||||
}
|
||||
else
|
||||
convert = identityFunction();
|
||||
}
|
||||
else if (toCategory == Type::Category::Enum)
|
||||
{
|
||||
@ -3325,9 +3392,6 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
.render();
|
||||
break;
|
||||
}
|
||||
case Type::Category::FixedPoint:
|
||||
solUnimplemented("Fixed point types not implemented.");
|
||||
break;
|
||||
case Type::Category::Struct:
|
||||
{
|
||||
solAssert(toCategory == Type::Category::Struct, "");
|
||||
@ -3376,11 +3440,23 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
("shift", shiftRightFunction(256 - from.numBytes() * 8))
|
||||
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
|
||||
.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)
|
||||
body =
|
||||
Whiskers("converted := <convert>(value)")
|
||||
("convert", conversionFunction(_from, IntegerType(160)))
|
||||
.render();
|
||||
("convert", conversionFunction(_from, IntegerType(160)))
|
||||
.render();
|
||||
else
|
||||
{
|
||||
// clear for conversion to longer bytes
|
||||
@ -3720,15 +3796,15 @@ string YulUtilFunctions::cleanupFunction(Type const& _type)
|
||||
templ("body", "cleaned := and(value, " + toCompactHexWithPrefix((u256(1) << type.numBits()) - 1) + ")");
|
||||
break;
|
||||
}
|
||||
case Type::Category::FixedPoint:
|
||||
templ("body", "cleaned := " + cleanupFunction(*dynamic_cast<FixedPointType const&>(_type).asIntegerType()) + "(value)");
|
||||
break;
|
||||
case Type::Category::RationalNumber:
|
||||
templ("body", "cleaned := value");
|
||||
break;
|
||||
case Type::Category::Bool:
|
||||
templ("body", "cleaned := iszero(iszero(value))");
|
||||
break;
|
||||
case Type::Category::FixedPoint:
|
||||
solUnimplemented("Fixed point types not implemented.");
|
||||
break;
|
||||
case Type::Category::Function:
|
||||
switch (dynamic_cast<FunctionType const&>(_type).kind())
|
||||
{
|
||||
|
@ -109,6 +109,10 @@ public:
|
||||
std::string typedShiftLeftFunction(Type const& _type, Type const& _amountType);
|
||||
std::string typedShiftRightFunction(Type const& _type, Type const& _amountType);
|
||||
|
||||
/// @returns the name of a function that shifts a decimal fixed point number by
|
||||
/// @a _decimal decimals (positive multiplies, negative divides).
|
||||
std::string fixedPointShiftFunction(int _digits, bool _signed);
|
||||
|
||||
/// @returns the name of a function which replaces the
|
||||
/// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant
|
||||
/// byte) by the _numBytes least significant bytes of `toInsert`.
|
||||
|
@ -797,6 +797,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
bool isSigned = false;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(commonType))
|
||||
isSigned = type->isSigned();
|
||||
if (auto type = dynamic_cast<FixedPointType const*>(commonType))
|
||||
isSigned = type->isSigned();
|
||||
|
||||
string args =
|
||||
expressionAsType(_binOp.leftExpression(), *commonType, true) +
|
||||
|
Loading…
Reference in New Issue
Block a user