Compound assignment.

This commit is contained in:
chriseth 2019-05-23 20:17:20 +02:00
parent 195a7ff61a
commit fb40063253
2 changed files with 81 additions and 46 deletions

View File

@ -129,21 +129,34 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var
bool IRGeneratorForStatements::visit(Assignment const& _assignment) bool IRGeneratorForStatements::visit(Assignment const& _assignment)
{ {
solUnimplementedAssert(_assignment.assignmentOperator() == Token::Assign, "");
_assignment.rightHandSide().accept(*this); _assignment.rightHandSide().accept(*this);
Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType(
&type(_assignment.leftHandSide()) &type(_assignment.leftHandSide())
); );
string intermediateValue = m_context.newYulVariable(); string value = m_context.newYulVariable();
m_code << "let " << intermediateValue << " := " << expressionAsType(_assignment.rightHandSide(), *intermediateType) << "\n"; m_code << "let " << value << " := " << expressionAsType(_assignment.rightHandSide(), *intermediateType) << "\n";
_assignment.leftHandSide().accept(*this); _assignment.leftHandSide().accept(*this);
solAssert(!!m_currentLValue, "LValue not retrieved."); solAssert(!!m_currentLValue, "LValue not retrieved.");
m_code << m_currentLValue->storeValue(intermediateValue, *intermediateType);
m_currentLValue.reset();
defineExpression(_assignment) << intermediateValue << "\n"; if (_assignment.assignmentOperator() != Token::Assign)
{
solAssert(type(_assignment.leftHandSide()) == *intermediateType, "");
solAssert(intermediateType->isValueType(), "Compound operators only available for value types.");
string leftIntermediate = m_context.newYulVariable();
m_code << "let " << leftIntermediate << " := " << m_currentLValue->retrieveValue() << "\n";
m_code << value << " := " << binaryOperation(
TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()),
*intermediateType,
leftIntermediate,
value
);
}
m_code << m_currentLValue->storeValue(value, *intermediateType);
m_currentLValue.reset();
defineExpression(_assignment) << value << "\n";
return false; return false;
} }
@ -319,27 +332,6 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
solUnimplementedAssert(false, "Unary operator not yet implemented"); solUnimplementedAssert(false, "Unary operator not yet implemented");
} }
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
{
string func;
if (_operation.getOperator() == Token::Not)
func = "iszero";
else if (_operation.getOperator() == Token::BitNot)
func = "not";
else
solAssert(false, "Invalid Token!");
defineExpression(_operation) <<
m_utils.cleanupFunction(type(_expr)) <<
"(" <<
func <<
"(" <<
m_context.variable(_expr) <<
")" <<
")\n";
}
bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{ {
solAssert(!!_binOp.annotation().commonType, ""); solAssert(!!_binOp.annotation().commonType, "");
@ -397,24 +389,10 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
} }
else else
{ {
if (IntegerType const* type = dynamic_cast<IntegerType const*>(commonType))
{
solUnimplementedAssert(!type->isSigned(), "");
string left = expressionAsType(_binOp.leftExpression(), *commonType); string left = expressionAsType(_binOp.leftExpression(), *commonType);
string right = expressionAsType(_binOp.rightExpression(), *commonType); string right = expressionAsType(_binOp.rightExpression(), *commonType);
string fun;
if (_binOp.getOperator() == Token::Add) defineExpression(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right);
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_binOp.getOperator() == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_binOp.getOperator() == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
else
solUnimplementedAssert(false, "");
defineExpression(_binOp) << fun << "(" << left << ", " << right << ")\n";
}
else
solUnimplementedAssert(false, "");
} }
return false; return false;
} }
@ -1088,6 +1066,55 @@ ostream& IRGeneratorForStatements::defineExpressionPart(Expression const& _expre
return m_code << "let " << m_context.variablePart(_expression, _part) << " := "; return m_code << "let " << m_context.variablePart(_expression, _part) << " := ";
} }
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
{
string func;
if (_operation.getOperator() == Token::Not)
func = "iszero";
else if (_operation.getOperator() == Token::BitNot)
func = "not";
else
solAssert(false, "Invalid Token!");
defineExpression(_operation) <<
m_utils.cleanupFunction(type(_expr)) <<
"(" <<
func <<
"(" <<
m_context.variable(_expr) <<
")" <<
")\n";
}
string IRGeneratorForStatements::binaryOperation(
langutil::Token _operator,
Type const& _type,
string const& _left,
string const& _right
)
{
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
{
solUnimplementedAssert(!type->isSigned(), "");
string fun;
if (_operator == Token::Add)
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_operator == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_operator == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
else
solUnimplementedAssert(false, "");
return fun + "(" + _left + ", " + _right + ")\n";
}
else
solUnimplementedAssert(false, "");
return {};
}
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
{ {
langutil::Token const op = _binOp.getOperator(); langutil::Token const op = _binOp.getOperator();

View File

@ -84,6 +84,14 @@ private:
void appendAndOrOperatorCode(BinaryOperation const& _binOp); void appendAndOrOperatorCode(BinaryOperation const& _binOp);
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr); void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
/// @returns code to perform the given binary operation in the given type on the two values.
std::string binaryOperation(
langutil::Token _op,
Type const& _type,
std::string const& _left,
std::string const& _right
);
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue); void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
void generateLoop( void generateLoop(
Statement const& _body, Statement const& _body,