[SMTChecker] Implementing compound bitwise And/Or/Xor operators

This commit is contained in:
Djordje Mijovic 2020-09-21 16:54:58 +02:00
parent 700cc4c9d3
commit 773e000227
3 changed files with 88 additions and 35 deletions

View File

@ -8,6 +8,7 @@ Compiler Features:
* SMTChecker: Support events and low-level logs. * SMTChecker: Support events and low-level logs.
* SMTChecker: Support ``revert()``. * SMTChecker: Support ``revert()``.
* SMTChecker: Support shifts. * SMTChecker: Support shifts.
* SMTChecker: Support compound and, or, and xor operators.
* SMTChecker: Support structs. * SMTChecker: Support structs.
* SMTChecker: Support ``type(T).min``, ``type(T).max``, and ``type(I).interfaceId``. * SMTChecker: Support ``type(T).min``, ``type(T).max``, and ``type(I).interfaceId``.
* Yul Optimizer: Prune unused parameters in functions. * Yul Optimizer: Prune unused parameters in functions.

View File

@ -357,7 +357,10 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
Token::AssignSub, Token::AssignSub,
Token::AssignMul, Token::AssignMul,
Token::AssignDiv, Token::AssignDiv,
Token::AssignMod Token::AssignMod,
Token::AssignBitAnd,
Token::AssignBitOr,
Token::AssignBitXor
}; };
Token op = _assignment.assignmentOperator(); Token op = _assignment.assignmentOperator();
if (op != Token::Assign && !compoundOps.count(op)) if (op != Token::Assign && !compoundOps.count(op))
@ -1381,6 +1384,59 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
return {value, valueUnbounded}; return {value, valueUnbounded};
} }
smtutil::Expression SMTEncoder::bitwiseOperation(
Token _op,
smtutil::Expression const& _left,
smtutil::Expression const& _right,
TypePointer const& _commonType
)
{
static set<Token> validOperators{
Token::BitAnd,
Token::BitOr,
Token::BitXor,
Token::SHL,
Token::SHR,
Token::SAR
};
solAssert(validOperators.count(_op), "");
solAssert(_commonType, "");
auto [bvSize, isSigned] = smt::typeBvSizeAndSignedness(_commonType);
auto bvLeft = smtutil::Expression::int2bv(_left, bvSize);
auto bvRight = smtutil::Expression::int2bv(_right, bvSize);
optional<smtutil::Expression> result;
switch (_op)
{
case Token::BitAnd:
result = bvLeft & bvRight;
break;
case Token::BitOr:
result = bvLeft | bvRight;
break;
case Token::BitXor:
result = bvLeft ^ bvRight;
break;
case Token::SHL:
result = bvLeft << bvRight;
break;
case Token::SHR:
solAssert(false, "");
case Token::SAR:
result = isSigned ?
smtutil::Expression::ashr(bvLeft, bvRight) :
bvLeft >> bvRight;
break;
default:
solAssert(false, "");
}
solAssert(result.has_value(), "");
return smtutil::Expression::bv2int(*result, isSigned);
}
void SMTEncoder::compareOperation(BinaryOperation const& _op) void SMTEncoder::compareOperation(BinaryOperation const& _op)
{ {
auto const& commonType = _op.annotation().commonType; auto const& commonType = _op.annotation().commonType;
@ -1457,39 +1513,12 @@ void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
auto commonType = _op.annotation().commonType; auto commonType = _op.annotation().commonType;
solAssert(commonType, ""); solAssert(commonType, "");
auto [bvSize, isSigned] = smt::typeBvSizeAndSignedness(commonType); defineExpr(_op, bitwiseOperation(
_op.getOperator(),
auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression(), commonType), bvSize); expr(_op.leftExpression(), commonType),
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression(), commonType), bvSize); expr(_op.rightExpression(), commonType),
commonType
optional<smtutil::Expression> result; ));
switch (op)
{
case Token::BitAnd:
result = bvLeft & bvRight;
break;
case Token::BitOr:
result = bvLeft | bvRight;
break;
case Token::BitXor:
result = bvLeft ^ bvRight;
break;
case Token::SHL:
result = bvLeft << bvRight;
break;
case Token::SHR:
solAssert(false, "");
case Token::SAR:
result = isSigned ?
smtutil::Expression::ashr(bvLeft, bvRight) :
bvLeft >> bvRight;
break;
default:
solAssert(false, "");
}
solAssert(result, "");
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
} }
void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op) void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op)
@ -1597,9 +1626,24 @@ smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment
{Token::AssignDiv, Token::Div}, {Token::AssignDiv, Token::Div},
{Token::AssignMod, Token::Mod} {Token::AssignMod, Token::Mod}
}; };
static map<Token, Token> const compoundToBitwise{
{Token::AssignBitAnd, Token::BitAnd},
{Token::AssignBitOr, Token::BitOr},
{Token::AssignBitXor, Token::BitXor}
};
Token op = _assignment.assignmentOperator(); Token op = _assignment.assignmentOperator();
solAssert(compoundToArithmetic.count(op), ""); solAssert(compoundToArithmetic.count(op) || compoundToBitwise.count(op), "");
auto decl = identifierToVariable(_assignment.leftHandSide()); auto decl = identifierToVariable(_assignment.leftHandSide());
if (compoundToBitwise.count(op))
return bitwiseOperation(
compoundToBitwise.at(op),
decl ? currentValue(*decl) : expr(_assignment.leftHandSide()),
expr(_assignment.rightHandSide()),
_assignment.annotation().type
);
auto values = arithmeticOperation( auto values = arithmeticOperation(
compoundToArithmetic.at(op), compoundToArithmetic.at(op),
decl ? currentValue(*decl) : expr(_assignment.leftHandSide()), decl ? currentValue(*decl) : expr(_assignment.leftHandSide()),

View File

@ -119,6 +119,14 @@ protected:
TypePointer const& _commonType, TypePointer const& _commonType,
Expression const& _expression Expression const& _expression
); );
smtutil::Expression bitwiseOperation(
Token _op,
smtutil::Expression const& _left,
smtutil::Expression const& _right,
TypePointer const& _commonType
);
void compareOperation(BinaryOperation const& _op); void compareOperation(BinaryOperation const& _op);
void booleanOperation(BinaryOperation const& _op); void booleanOperation(BinaryOperation const& _op);
void bitwiseOperation(BinaryOperation const& _op); void bitwiseOperation(BinaryOperation const& _op);