let get_bitwise_shift_assertion
~simplify_constants:simplify_constants
~warning:warning
exp shiftop loperand roperand =
(* - (1) right operand should be nonnegative and
strictly less than the width of promoted left operand:
now done by get_bitwise_shift_right_operand_assertion
- (2) (since signed version) left operand should be nonnegative
(implementation defined for right shift, undefined for left shift)
- (3) (for signed left shift) (left operand should be nonnegative: see (2), and)
result should be representable in result type *)
let t = Cil.typeOf exp in
let size = bitsSizeOf t in
let () =
if not(size = bitsSizeOf (Cil.typeOf loperand) && size <= 64)
(* size of result type should be size of left (promoted) operand *)
then (
rte_warn "problem with bitsSize of %a: not treated" d_exp exp ;
)
in
let maxValResult = (* compute greatest representable "size bits" (signed) integer *)
get_signed_max size
(*
let max64 = Int64.max_int
and shiftright_value = 64 - size
in if shiftright_value > 0 then Int64.shift_right max64 shiftright_value else max64
*)
in let assertion_2 () =
let term = translate_C_expr_to_term loperand
in Logic_const.prel (Rge, term, Cil.lzero ())
and assertion_3 () =
let term = translate_C_expr_to_term ~cast:false exp
in (* signed result is representable in result type if loperand times 2^roperand
(where loperand and roperand are nonnegative),
which should be equal to term (obtained with a shift),
is less than the maximal value for the result type *)
(* no cast to int since we check "true result" which is an integer*)
Logic_const.prel (Rle, term, Cil.lconstant maxValResult)
in let problem_with_assertion_2 () =
if simplify_constants then (
match get_expr_val loperand with
| None -> (false,false)
| Some c64 ->
(* left operand is constant: check it is nonnegative *)
if (Int64.compare c64 Int64.zero >= 0)
then (true, true) (* constant operator and assertion holds *)
else (true,false) (* constant operator and assertion does not hold *)
) else (false,false)
and problem_with_assertion_3 () =
if simplify_constants then (
match get_expr_val loperand, get_expr_val roperand with
| None,_
| _, None -> (false,false)
| Some lval64, Some rval64 ->
(* both operands are constant:
check result is representable in result type *)
if (Int64.compare lval64 Int64.zero <= 0) ||
(Int64.compare rval64 (Int64.of_int 64) >= 0) then
(true,false) (* constant operators and assertion does not hold *)
else
let result_true_val =
Int.shift_left (Int.of_int64 lval64) (Int.of_int64 rval64)
in
if Int.compare result_true_val (Int.of_int64 maxValResult) > 0
then (true,false) (* constant operators and assertion does not hold *)
else (true,true) (* constant operators and assertion holds *)
) else (false,false)
in let proceed_with_assertion_3 lassert =
if (shiftop = Shiftlt) then (
match problem_with_assertion_3 () with
| (true,false) ->
let assertion = assertion_3 () in
if warning then (
rte_warn
"shift assert broken (signed overflow): %a"
d_predicate_named assertion
)
;
((assertion, Some (make_check_false ())))::lassert
| (true,true) -> lassert
| (false,_) -> (assertion_3 (), None)::lassert
) else lassert
in
match problem_with_assertion_2 () with
| (true,false) ->
let assertion = assertion_2 () in
if warning then (
rte_warn
"shift assert broken (left operand should be nonnegative): %a"
d_predicate_named assertion
)
;
(* do not proceed with assertion 3: left operand is negative,
hence result is implementation defined anyway for left shift *)
[ (assertion, Some (make_check_false ())) ]
| (true,true) -> proceed_with_assertion_3 [ ]
| (false,_) -> proceed_with_assertion_3 [ (assertion_2 (), None) ]