let get_bitwise_lshift_unsigned_assertion
    ~simplify_constants:simplify_constants
    ~warning:warning
    exp loperand roperand =
  (* result should be representable in result type *)
  let t = Cil.typeOf exp in
  let size = bitsSizeOf t in
  let maxValResult =
    (* compute greatest reprensentable "size bits" unsigned integer *)
    max_unsigned_number size
  in let ov_assertion () =
       let term = translate_C_expr_to_term ~cast:false exp
       in (* unsigned 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_ov_assertion () =
          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 *)

              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
        match problem_with_ov_assertion () with
        | (true,false->
          let assertion = ov_assertion () in
          if warning then
            rte_warn
              fmt_warn_shift_assert3
              d_predicate_named assertion;
          [ assertion, Some Property_status.False_if_reachable ]
        | (true,true)  -> [ ]
        | (false,_)    -> [ ov_assertion (), None ]