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 fmt_warn_bad_bitsize d_exp exp ;
)
in
let maxValResult =
(* compute greatest representable "size bits" (signed) integer *)
max_signed_number 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 My_bigint.ge c64 My_bigint.zero
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 (My_bigint.le lval64 My_bigint.zero)
|| (My_bigint.ge rval64 (My_bigint.of_int 64)) then
(true,false)(* constant operators and assertion does not hold *)
else
let result_true_val = Int.shift_left lval64 rval64 in
if Int.gt result_true_val maxValResult
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 begin
match problem_with_assertion_3 () with
| (true,false) ->
let assertion = assertion_3 () in
if warning then
rte_warn
fmt_warn_shift_assert1
d_predicate_named assertion;
(assertion, Some Property_status.False_if_reachable)::lassert
| (true,true) -> lassert
| (false,_) -> (assertion_3 (), None)::lassert
end else
lassert
in
match problem_with_assertion_2 () with
| true, false ->
let assertion = assertion_2 () in
if warning then
rte_warn
fmt_warn_shift_assert2
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 Property_status.False_if_reachable ]
| true, true -> proceed_with_assertion_3 [ ]
| false, _ ->
proceed_with_assertion_3 [ assertion_2 (), None ]