Merge pull request #6660 from ethereum/shortCircuiting

Short circuiting
This commit is contained in:
chriseth 2019-05-07 16:55:12 +02:00 committed by GitHub
commit 133fd18223
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 5 deletions

View File

@ -131,6 +131,21 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
return false;
}
bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
{
if (_tuple.isInlineArray())
solUnimplementedAssert(false, "");
else
{
solUnimplementedAssert(!_tuple.annotation().lValueRequested, "");
solUnimplementedAssert(_tuple.components().size() == 1, "");
solAssert(_tuple.components().front(), "");
_tuple.components().front()->accept(*this);
defineExpression(_tuple) << m_context.variable(*_tuple.components().front()) << "\n";
}
return false;
}
bool IRGeneratorForStatements::visit(ForStatement const& _for)
{
m_code << "for {\n";
@ -199,16 +214,23 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
solUnimplementedAssert(false, "");
}
void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{
solAssert(!!_binOp.annotation().commonType, "");
TypePointer commonType = _binOp.annotation().commonType;
langutil::Token op = _binOp.getOperator();
if (op == Token::And || op == Token::Or)
// special case: short-circuiting
solUnimplementedAssert(false, "");
else if (commonType->category() == Type::Category::RationalNumber)
{
// This can short-circuit!
appendAndOrOperatorCode(_binOp);
return false;
}
_binOp.leftExpression().accept(*this);
_binOp.rightExpression().accept(*this);
if (commonType->category() == Type::Category::RationalNumber)
defineExpression(_binOp) <<
toCompactHexWithPrefix(commonType->literalValue(nullptr)) <<
"\n";
@ -259,6 +281,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
else
solUnimplementedAssert(false, "");
}
return false;
}
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
@ -429,6 +452,24 @@ ostream& IRGeneratorForStatements::defineExpression(Expression const& _expressio
return m_code << "let " << m_context.variable(_expression) << " := ";
}
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
{
langutil::Token const op = _binOp.getOperator();
solAssert(op == Token::Or || op == Token::And, "");
_binOp.leftExpression().accept(*this);
string value = m_context.variable(_binOp);
m_code << "let " << value << " := " << m_context.variable(_binOp.leftExpression()) << "\n";
if (op == Token::Or)
m_code << "if iszero(" << value << ") {\n";
else
m_code << "if " << value << " {\n";
_binOp.rightExpression().accept(*this);
m_code << value << " := " + m_context.variable(_binOp.rightExpression()) << "\n";
m_code << "}\n";
}
void IRGeneratorForStatements::setLValue(Expression const& _expression, unique_ptr<IRLValue> _lvalue)
{
solAssert(!m_currentLValue, "");

View File

@ -47,12 +47,13 @@ public:
void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
bool visit(Assignment const& _assignment) override;
bool visit(TupleExpression const& _tuple) override;
bool visit(ForStatement const& _forStatement) override;
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;
bool visit(BinaryOperation const& _binOp) override;
void endVisit(FunctionCall const& _funCall) override;
bool visit(InlineAssembly const& _inlineAsm) override;
bool visit(Identifier const& _identifier) override;
@ -64,6 +65,8 @@ private:
std::string expressionAsType(Expression const& _expression, Type const& _to);
std::ostream& defineExpression(Expression const& _expression);
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
static Type const& type(Expression const& _expression);

View File

@ -0,0 +1,17 @@
contract C {
function or(uint x) public returns (bool t, uint y) {
t = (x == 0 || ((x = 8) > 0));
y = x;
}
function and(uint x) public returns (bool t, uint y) {
t = (x == 0 && ((x = 8) > 0));
y = x;
}
}
// ====
// compileViaYul: true
// ----
// or(uint256): 0 -> true, 0
// and(uint256): 0 -> true, 8
// or(uint256): 1 -> true, 8
// and(uint256): 1 -> false, 1