IR generation for shifts

This commit is contained in:
Alex Beregszaszi
2020-05-06 19:14:23 +02:00
committed by chriseth
parent 3a93080ca9
commit 327c75bc1b
32 changed files with 236 additions and 18 deletions
@@ -254,29 +254,53 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional)
bool IRGeneratorForStatements::visit(Assignment const& _assignment)
{
_assignment.rightHandSide().accept(*this);
Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType(
&type(_assignment.leftHandSide())
);
IRVariable value = convert(_assignment.rightHandSide(), *intermediateType);
Token assignmentOperator = _assignment.assignmentOperator();
Token binaryOperator =
assignmentOperator == Token::Assign ?
assignmentOperator :
TokenTraits::AssignmentToBinaryOp(assignmentOperator);
Type const* rightIntermediateType =
TokenTraits::isShiftOp(binaryOperator) ?
type(_assignment.rightHandSide()).mobileType() :
type(_assignment.rightHandSide()).closestTemporaryType(
&type(_assignment.leftHandSide())
);
solAssert(rightIntermediateType, "");
IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType);
_assignment.leftHandSide().accept(*this);
solAssert(!!m_currentLValue, "LValue not retrieved.");
if (_assignment.assignmentOperator() != Token::Assign)
if (assignmentOperator != Token::Assign)
{
solAssert(type(_assignment.leftHandSide()) == *intermediateType, "");
solAssert(intermediateType->isValueType(), "Compound operators only available for value types.");
solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types.");
solAssert(rightIntermediateType->isValueType(), "Compound operators only available for value types.");
IRVariable leftIntermediate = readFromLValue(*m_currentLValue);
m_code << value.name() << " := " << binaryOperation(
TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()),
*intermediateType,
leftIntermediate.name(),
value.name()
);
if (TokenTraits::isShiftOp(binaryOperator))
{
solAssert(type(_assignment) == leftIntermediate.type(), "");
solAssert(type(_assignment) == type(_assignment.leftHandSide()), "");
define(_assignment) << shiftOperation(binaryOperator, leftIntermediate, value);
writeToLValue(*m_currentLValue, IRVariable(_assignment));
m_currentLValue.reset();
return false;
}
else
{
solAssert(type(_assignment.leftHandSide()) == *rightIntermediateType, "");
m_code << value.name() << " := " << binaryOperation(
binaryOperator,
*rightIntermediateType,
leftIntermediate.name(),
value.name()
);
}
}
writeToLValue(*m_currentLValue, value);
m_currentLValue.reset();
if (*_assignment.annotation().type != *TypeProvider::emptyTuple())
define(_assignment, value);
@@ -541,6 +565,12 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
solAssert(false, "Unknown comparison operator.");
define(_binOp) << expr << "\n";
}
else if (TokenTraits::isShiftOp(op))
{
IRVariable left = convert(_binOp.leftExpression(), *commonType);
IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType());
define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n";
}
else
{
string left = expressionAsType(_binOp.leftExpression(), *commonType);
@@ -1921,6 +1951,10 @@ string IRGeneratorForStatements::binaryOperation(
string const& _right
)
{
solAssert(
!TokenTraits::isShiftOp(_operator),
"Have to use specific shift operation function for shifts."
);
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
{
string fun;
@@ -1964,6 +1998,31 @@ string IRGeneratorForStatements::binaryOperation(
return {};
}
std::string IRGeneratorForStatements::shiftOperation(
langutil::Token _operator,
IRVariable const& _value,
IRVariable const& _amountToShift
)
{
IntegerType const* amountType = dynamic_cast<IntegerType const*>(&_amountToShift.type());
solAssert(amountType, "");
solAssert(_operator == Token::SHL || _operator == Token::SAR, "");
return
Whiskers(R"(
<shift>(<value>, <amount>)
)")
("shift",
_operator == Token::SHL ?
m_utils.typedShiftLeftFunction(_value.type(), *amountType) :
m_utils.typedShiftRightFunction(_value.type(), *amountType)
)
("value", _value.name())
("amount", _amountToShift.name())
.render();
}
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
{
langutil::Token const op = _binOp.getOperator();