let get_multsubadd_assertion
~simplify_constants:simplify_constants
~warning:warning
full_expr op expr1 expr2 =
let t = Cil.typeOf full_expr in
let size = bitsSizeOf t
in if (size > 64) then (
rte_warn fmt_warn_bitsize_over_64 d_exp full_expr ;
[]
)
else
let (minType,maxType) = (min_signed_number size, max_signed_number size)
in
let full_add_term () =
let term1 = translate_C_expr_to_term ~cast:false expr1
and term2 = translate_C_expr_to_term ~cast:false expr2
in Logic_const.term (TBinOp (op, term1,term2)) (Ctype t)
in
let assertion_le () = assertion_le (full_add_term ()) maxType
and assertion_ge () = assertion_ge (full_add_term ()) minType in
let full_assertion () =
Logic_const.pand (assertion_le (), assertion_ge ())
in
if simplify_constants then begin
match get_expr_val expr1, get_expr_val expr2 with
| Some a64, Some b64 ->
let big_a64 = a64
and big_b64 = b64
in
if op = MinusA then
let big_diff = Int.sub big_a64 big_b64
in if Int.lt big_diff minType then
let assertion = assertion_ge () in
if warning then
rte_warn
fmt_signed_overflow_assert
d_predicate_named assertion;
[ assertion, Some Property_status.False_if_reachable ]
else
[ ]
else if op = PlusA then
let big_add = Int.add big_a64 big_b64 in
if Int.gt big_add maxType then
let assertion = assertion_le () in
if warning then
rte_warn
fmt_signed_overflow_assert
d_predicate_named assertion;
[ assertion, Some Property_status.False_if_reachable ]
else
[ ]
else (
assert(op = Mult) ;
let big_mult = Int.mul big_a64 big_b64 in
let b_ov = Int.gt big_mult maxType in
if b_ov then
let assertion = assertion_le () in
if warning then
rte_warn
fmt_signed_overflow_assert
d_predicate_named assertion ;
[ assertion, Some Property_status.False_if_reachable ]
else
let b_uv = Int.lt big_mult minType in
if b_uv then
let assertion = assertion_ge () in
if warning then
rte_warn
fmt_signed_overflow_assert
d_predicate_named assertion ;
[ assertion, Some Property_status.False_if_reachable ]
else [ ])
| Some a64, None
| None, Some a64 ->
if op = MinusA then
[ assertion_ge (), None ]
else if op = PlusA then
[ assertion_le (), None ]
else begin
assert(op = Mult);
if (My_bigint.equal a64 My_bigint.zero) ||
(My_bigint.equal a64 My_bigint.one)
then []
else
if My_bigint.equal a64 My_bigint.minus_one then
[ assertion_le (), None ]
else
[ full_assertion (), None ]
end
| None,None ->
[ full_assertion (), None ]
end else
[ full_assertion (), None ]