diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 53c0586ea..496625d0a 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -115,7 +115,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) solUnimplementedAssert(_assignment.assignmentOperator() == Token::Assign, ""); _assignment.rightHandSide().accept(*this); - Type const* intermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType( + Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( &type(_assignment.leftHandSide()) ); string intermediateValue = m_context.newYulVariable(); @@ -189,18 +189,59 @@ void IRGeneratorForStatements::endVisit(Return const& _return) m_code << "return_flag := 0\n" << "break\n"; } +void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation) +{ + if (type(_unaryOperation).category() == Type::Category::RationalNumber) + defineExpression(_unaryOperation) << + formatNumber(type(_unaryOperation).literalValue(nullptr)) << + "\n"; + else + solUnimplementedAssert(false, ""); +} + void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) { solAssert(!!_binOp.annotation().commonType, ""); TypePointer commonType = _binOp.annotation().commonType; + langutil::Token op = _binOp.getOperator(); - if (_binOp.getOperator() == Token::And || _binOp.getOperator() == Token::Or) + if (op == Token::And || op == Token::Or) // special case: short-circuiting solUnimplementedAssert(false, ""); else if (commonType->category() == Type::Category::RationalNumber) defineExpression(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; + else if (TokenTraits::isCompareOp(op)) + { + solUnimplementedAssert(commonType->category() != Type::Category::Function, ""); + solAssert(commonType->isValueType(), ""); + bool isSigned = false; + if (auto type = dynamic_cast(commonType)) + isSigned = type->isSigned(); + + string args = + expressionAsType(_binOp.leftExpression(), *commonType) + + ", " + + expressionAsType(_binOp.rightExpression(), *commonType); + + string expr; + if (op == Token::Equal) + expr = "eq(" + move(args) + ")"; + else if (op == Token::NotEqual) + expr = "iszero(eq(" + move(args) + "))"; + else if (op == Token::GreaterThanOrEqual) + expr = "iszero(" + string(isSigned ? "slt(" : "lt(") + move(args) + "))"; + else if (op == Token::LessThanOrEqual) + expr = "iszero(" + string(isSigned ? "sgt(" : "gt(") + move(args) + "))"; + else if (op == Token::GreaterThan) + expr = (isSigned ? "sgt(" : "gt(") + move(args) + ")"; + else if (op == Token::LessThan) + expr = (isSigned ? "slt(" : "lt(") + move(args) + ")"; + else + solAssert(false, "Unknown comparison operator."); + defineExpression(_binOp) << expr << "\n"; + } else { solUnimplementedAssert(_binOp.getOperator() == Token::Add, ""); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index f68e9042f..af5dd89a2 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -51,6 +51,7 @@ public: bool visit(Continue const& _continueStatement) override; bool visit(Break const& _breakStatement) override; void endVisit(Return const& _return) override; + void endVisit(UnaryOperation const& _unaryOperation) override; void endVisit(BinaryOperation const& _binOp) override; void endVisit(FunctionCall const& _funCall) override; bool visit(InlineAssembly const& _inlineAsm) override; diff --git a/test/libsolidity/semanticTests/viaYul/comparison.sol b/test/libsolidity/semanticTests/viaYul/comparison.sol new file mode 100644 index 000000000..c42ae6df9 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/comparison.sol @@ -0,0 +1,74 @@ +contract C { + function f(address a) public pure returns (bool) { + return a == address(0); + } + function g() public pure returns (bool) { + return bytes3("abc") == bytes4("abc"); + } + function lt(uint a, uint b) public pure returns (bool) { + return a < b; + } + function slt(int a, int b) public pure returns (bool) { + return a < b; + } + function lte(uint a, uint b) public pure returns (bool) { + return a <= b; + } + function slte(int a, int b) public pure returns (bool) { + return a <= b; + } + function gt(uint a, uint b) public pure returns (bool) { + return a > b; + } + function sgt(int a, int b) public pure returns (bool) { + return a > b; + } + function gte(uint a, uint b) public pure returns (bool) { + return a >= b; + } + function sgte(int a, int b) public pure returns (bool) { + return a >= b; + } + function eq(uint a, uint b) public pure returns (bool) { + return a == b; + } + function neq(uint a, uint b) public pure returns (bool) { + return a != b; + } +} +// ==== +// compileViaYul: true +// ---- +// f(address): 0x1234 -> false +// f(address): 0x00 -> true +// g() -> true +// lt(uint256,uint256): 4, 5 -> true +// lt(uint256,uint256): 5, 5 -> false +// lt(uint256,uint256): 6, 5 -> false +// gt(uint256,uint256): 4, 5 -> false +// gt(uint256,uint256): 5, 5 -> false +// gt(uint256,uint256): 6, 5 -> true +// lte(uint256,uint256): 4, 5 -> true +// lte(uint256,uint256): 5, 5 -> true +// lte(uint256,uint256): 6, 5 -> false +// gte(uint256,uint256): 4, 5 -> false +// gte(uint256,uint256): 5, 5 -> true +// gte(uint256,uint256): 6, 5 -> true +// eq(uint256,uint256): 4, 5 -> false +// eq(uint256,uint256): 5, 5 -> true +// eq(uint256,uint256): 6, 5 -> false +// neq(uint256,uint256): 4, 5 -> true +// neq(uint256,uint256): 5, 5 -> false +// neq(uint256,uint256): 6, 5 -> true +// slt(int256,int256): -1, 0 -> true +// slt(int256,int256): 0, 0 -> false +// slt(int256,int256): 1, 0 -> false +// sgt(int256,int256): -1, 0 -> false +// sgt(int256,int256): 0, 0 -> false +// sgt(int256,int256): 1, 0 -> true +// slte(int256,int256): -1, 0 -> true +// slte(int256,int256): 0, 0 -> true +// slte(int256,int256): 1, 0 -> false +// sgte(int256,int256): -1, 0 -> false +// sgte(int256,int256): 0, 0 -> true +// sgte(int256,int256): 1, 0 -> true