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 () =
    if not (size <= 32)
      (* 64 bits size "requires" representing a constant
         which does not hold in a Cil constant
         (as long as it remains an int64 and not a big integer) *)

    then rte_warn "problem with bitsSize of %a: not treated" d_exp exp ;
  in let maxValResult = (* compute greatest reprensentable "size bits" unsigned integer *)
      get_unsigned_max 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 (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
    match problem_with_ov_assertion () with
      | (true,false->
          let assertion = ov_assertion () in
            if warning then (
              rte_warn
                "shift assert broken (unsigned overflow): %a" d_predicate_named assertion
            )
            ;
            [ (assertion, Some (make_check_false())) ]
      | (true,true)  -> [ ]
      | (false,_)    -> [ (ov_assertion (), None) ]