From 3f9f725737dd04485211fedc8533fdac983f2b04 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 18 Nov 2016 17:13:20 -0600 Subject: Fix licensing headers Signed-off-by: VoR0220 --- libsolidity/codegen/ExpressionCompiler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen/ExpressionCompiler.cpp') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7a328528..58330764 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - cpp-ethereum is distributed in the hope that it will be useful, + solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . + along with solidity. If not, see . */ /** * @author Christian -- cgit v1.2.3 From f1bc979c0f2586b69909f36af48362d7dc9da9e7 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 17 Nov 2016 23:22:09 +0000 Subject: Use solUnimplemented wherever possible --- libsolidity/codegen/ExpressionCompiler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen/ExpressionCompiler.cpp') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 58330764..5748d818 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1252,7 +1252,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) case Type::Category::StringLiteral: break; // will be done during conversion default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now.")); + solUnimplemented("Only integer, boolean and string literals implemented for now."); } } @@ -1392,7 +1392,7 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) { - BOOST_THROW_EXCEPTION(UnimplementedFeatureError() << errinfo_comment("Shift operators not yet implemented.")); + solUnimplemented("Shift operators not yet implemented."); switch (_operator) { case Token::SHL: -- cgit v1.2.3 From b8b4f5e9f9a89eac1218551b5da322b41c7813f4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 30 Apr 2016 00:15:22 +0100 Subject: Support bitshifting in variables --- libsolidity/codegen/ExpressionCompiler.cpp | 49 +++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'libsolidity/codegen/ExpressionCompiler.cpp') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5748d818..d28ffed8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -211,6 +211,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) Token::Value op = _assignment.assignmentOperator(); if (op != Token::Assign) // compound assignment { + Token::Value target_op = Token::AssignmentToBinaryOp(op); solUnimplementedAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); @@ -221,7 +222,11 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) // value lvalue_ref value lvalue_ref } m_currentLValue->retrieveValue(_assignment.location(), true); - appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.annotation().type); + if (Token::isShiftOp(target_op)) + // shift only cares about the signedness of both sides + appendShiftOperatorCode(target_op, *_assignment.leftHandSide().annotation().type, *_assignment.rightHandSide().annotation().type); + else + appendOrdinaryBinaryOperatorCode(target_op, *_assignment.annotation().type); if (lvalueSize > 0) { solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); @@ -361,7 +366,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) else { bool cleanupNeeded = false; - if (Token::isCompareOp(c_op)) + if (Token::isCompareOp(c_op) || Token::isShiftOp(c_op)) cleanupNeeded = true; if (commonType.category() == Type::Category::Integer && (c_op == Token::Div || c_op == Token::Mod)) cleanupNeeded = true; @@ -386,7 +391,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) leftExpression.accept(*this); utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); } - if (Token::isCompareOp(c_op)) + if (Token::isShiftOp(c_op)) + // shift only cares about the signedness of both sides + appendShiftOperatorCode(c_op, *leftExpression.annotation().type, *rightExpression.annotation().type); + else if (Token::isCompareOp(c_op)) appendCompareOperatorCode(c_op, commonType); else appendOrdinaryBinaryOperatorCode(c_op, commonType); @@ -1326,8 +1334,6 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator appendArithmeticOperatorCode(_operator, _type); else if (Token::isBitOp(_operator)) appendBitOperatorCode(_operator); - else if (Token::isShiftOp(_operator)) - appendShiftOperatorCode(_operator); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); } @@ -1390,17 +1396,44 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType) { - solUnimplemented("Shift operators not yet implemented."); + // stack: rvalue lvalue + + bool c_leftSigned = false; + if (auto leftType = dynamic_cast(&_leftType)) + c_leftSigned = leftType->isSigned(); + else + solUnimplemented("Only IntegerType can be shifted."); + + // The RValue can be a RationalNumberType too. + bool c_rightSigned = false; + if (auto rightType = dynamic_cast(&_rightType)) + { + solAssert(rightType->integerType(), "integerType() called for fractional number."); + c_rightSigned = rightType->integerType()->isSigned(); + } + else if (auto rightType = dynamic_cast(&_rightType)) + c_rightSigned = rightType->isSigned(); + else + solUnimplemented("Not implemented yet - FixedPointType."); + + // shift with negative rvalue throws exception + if (c_rightSigned) + { + m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } + switch (_operator) { case Token::SHL: + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_leftSigned ? Instruction::SDIV : Instruction::DIV); break; case Token::SHR: - break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator.")); } -- cgit v1.2.3 From 273804503096d8d5d0c9d1fcece48da871f2d90f Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 6 Dec 2016 23:45:17 +0100 Subject: Cleaner shift handling and type conversion for binary operations. --- libsolidity/codegen/ExpressionCompiler.cpp | 119 ++++++++++++++++++----------- 1 file changed, 75 insertions(+), 44 deletions(-) (limited to 'libsolidity/codegen/ExpressionCompiler.cpp') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index d28ffed8..afe91c5c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -197,22 +197,37 @@ bool ExpressionCompiler::visit(Conditional const& _condition) bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); + Token::Value op = _assignment.assignmentOperator(); + Token::Value binOp = op == Token::Assign ? op : Token::AssignmentToBinaryOp(op); + Type const& leftType = *_assignment.leftHandSide().annotation().type; + if (leftType.category() == Type::Category::Tuple) + { + solAssert(*_assignment.annotation().type == TupleType(), ""); + solAssert(op == Token::Assign, ""); + } + else + solAssert(*_assignment.annotation().type == leftType, ""); + bool cleanupNeeded = false; + if (op != Token::Assign) + cleanupNeeded = cleanupNeededForOp(leftType.category(), binOp); _assignment.rightHandSide().accept(*this); // Perform some conversion already. This will convert storage types to memory and literals // to their actual type, but will not convert e.g. memory to storage. - TypePointer type = _assignment.rightHandSide().annotation().type->closestTemporaryType( - _assignment.leftHandSide().annotation().type - ); - utils().convertType(*_assignment.rightHandSide().annotation().type, *type); + TypePointer rightIntermediateType; + if (op != Token::Assign && Token::isShiftOp(binOp)) + rightIntermediateType = _assignment.rightHandSide().annotation().type->mobileType(); + else + rightIntermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType( + _assignment.leftHandSide().annotation().type + ); + utils().convertType(*_assignment.rightHandSide().annotation().type, *rightIntermediateType, cleanupNeeded); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - Token::Value op = _assignment.assignmentOperator(); if (op != Token::Assign) // compound assignment { - Token::Value target_op = Token::AssignmentToBinaryOp(op); - solUnimplementedAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); + solAssert(leftType.isValueType(), "Compound operators only available for value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); if (lvalueSize > 0) @@ -222,11 +237,17 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) // value lvalue_ref value lvalue_ref } m_currentLValue->retrieveValue(_assignment.location(), true); - if (Token::isShiftOp(target_op)) - // shift only cares about the signedness of both sides - appendShiftOperatorCode(target_op, *_assignment.leftHandSide().annotation().type, *_assignment.rightHandSide().annotation().type); + utils().convertType(leftType, leftType, cleanupNeeded); + + Token::Value targetOp = Token::AssignmentToBinaryOp(op); + + if (Token::isShiftOp(targetOp)) + appendShiftOperatorCode(targetOp, leftType, *rightIntermediateType); else - appendOrdinaryBinaryOperatorCode(target_op, *_assignment.annotation().type); + { + solAssert(leftType == *rightIntermediateType, ""); + appendOrdinaryBinaryOperatorCode(targetOp, leftType); + } if (lvalueSize > 0) { solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); @@ -235,7 +256,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP; } } - m_currentLValue->storeValue(*type, _assignment.location()); + m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); m_currentLValue.reset(); return false; } @@ -356,20 +377,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) Expression const& leftExpression = _binaryOperation.leftExpression(); Expression const& rightExpression = _binaryOperation.rightExpression(); solAssert(!!_binaryOperation.annotation().commonType, ""); - Type const& commonType = *_binaryOperation.annotation().commonType; + TypePointer const& commonType = _binaryOperation.annotation().commonType; Token::Value const c_op = _binaryOperation.getOperator(); if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); - else if (commonType.category() == Type::Category::RationalNumber) - m_context << commonType.literalValue(nullptr); + else if (commonType->category() == Type::Category::RationalNumber) + m_context << commonType->literalValue(nullptr); else { - bool cleanupNeeded = false; - if (Token::isCompareOp(c_op) || Token::isShiftOp(c_op)) - cleanupNeeded = true; - if (commonType.category() == Type::Category::Integer && (c_op == Token::Div || c_op == Token::Mod)) - cleanupNeeded = true; + bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op); + + TypePointer leftTargetType = commonType; + TypePointer rightTargetType = Token::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType; // for commutative operators, push the literal as late as possible to allow improved optimization auto isLiteral = [](Expression const& _e) @@ -380,24 +400,24 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) if (swap) { leftExpression.accept(*this); - utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded); rightExpression.accept(*this); - utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded); } else { rightExpression.accept(*this); - utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded); leftExpression.accept(*this); - utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded); } if (Token::isShiftOp(c_op)) // shift only cares about the signedness of both sides - appendShiftOperatorCode(c_op, *leftExpression.annotation().type, *rightExpression.annotation().type); + appendShiftOperatorCode(c_op, *leftTargetType, *rightTargetType); else if (Token::isCompareOp(c_op)) - appendCompareOperatorCode(c_op, commonType); + appendCompareOperatorCode(c_op, *commonType); else - appendOrdinaryBinaryOperatorCode(c_op, commonType); + appendOrdinaryBinaryOperatorCode(c_op, *commonType); } // do not visit the child nodes, we already did that explicitly @@ -1396,30 +1416,31 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType) +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType) { - // stack: rvalue lvalue + // stack: shift_amount value_to_shift - bool c_leftSigned = false; - if (auto leftType = dynamic_cast(&_leftType)) - c_leftSigned = leftType->isSigned(); + bool c_valueSigned = false; + if (auto valueType = dynamic_cast(&_valueType)) + c_valueSigned = valueType->isSigned(); else - solUnimplemented("Only IntegerType can be shifted."); + solAssert(dynamic_cast(&_valueType), "Only integer and fixed bytes type supported for shifts."); - // The RValue can be a RationalNumberType too. - bool c_rightSigned = false; - if (auto rightType = dynamic_cast(&_rightType)) + // The amount can be a RationalNumberType too. + bool c_amountSigned = false; + if (auto amountType = dynamic_cast(&_shiftAmountType)) { - solAssert(rightType->integerType(), "integerType() called for fractional number."); - c_rightSigned = rightType->integerType()->isSigned(); + // This should be handled by the type checker. + solAssert(amountType->integerType(), ""); + solAssert(!amountType->integerType()->isSigned(), ""); } - else if (auto rightType = dynamic_cast(&_rightType)) - c_rightSigned = rightType->isSigned(); + else if (auto amountType = dynamic_cast(&_shiftAmountType)) + c_amountSigned = amountType->isSigned(); else - solUnimplemented("Not implemented yet - FixedPointType."); + solAssert(false, "Invalid shift amount type."); - // shift with negative rvalue throws exception - if (c_rightSigned) + // shift by negative amount throws exception + if (c_amountSigned) { m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; m_context.appendConditionalJumpTo(m_context.errorTag()); @@ -1431,7 +1452,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: - m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_leftSigned ? Instruction::SDIV : Instruction::DIV); + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_valueSigned ? Instruction::SDIV : Instruction::DIV); break; case Token::SHR: default: @@ -1721,6 +1742,16 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) setLValue(_expression, *_expression.annotation().type); } +bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) +{ + if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) + return true; + else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod)) + return true; + else + return false; +} + CompilerUtils ExpressionCompiler::utils() { return CompilerUtils(m_context); -- cgit v1.2.3 From e9d3327ad6883acc6db8306bb7fa5ccbd802af9c Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 13 Dec 2016 16:50:50 +0100 Subject: Use correct type for storing. --- libsolidity/codegen/ExpressionCompiler.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'libsolidity/codegen/ExpressionCompiler.cpp') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index afe91c5c..a7fb8408 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -225,7 +225,9 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - if (op != Token::Assign) // compound assignment + if (op == Token::Assign) + m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); + else // compound assignment { solAssert(leftType.isValueType(), "Compound operators only available for value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); @@ -239,14 +241,12 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_currentLValue->retrieveValue(_assignment.location(), true); utils().convertType(leftType, leftType, cleanupNeeded); - Token::Value targetOp = Token::AssignmentToBinaryOp(op); - - if (Token::isShiftOp(targetOp)) - appendShiftOperatorCode(targetOp, leftType, *rightIntermediateType); + if (Token::isShiftOp(binOp)) + appendShiftOperatorCode(binOp, leftType, *rightIntermediateType); else { solAssert(leftType == *rightIntermediateType, ""); - appendOrdinaryBinaryOperatorCode(targetOp, leftType); + appendOrdinaryBinaryOperatorCode(binOp, leftType); } if (lvalueSize > 0) { @@ -255,8 +255,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) for (unsigned i = 0; i < itemSize; ++i) m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP; } + m_currentLValue->storeValue(*_assignment.annotation().type, _assignment.location()); } - m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); m_currentLValue.reset(); return false; } -- cgit v1.2.3