let eval_binop_int ~with_alarms ?typ ~te1 ev1 op ev2 =
  match op with
    | PlusPI | IndexPI -> V.add_untyped (osizeof_pointed te1) ev1 ev2
    | MinusPI -> V.add_untyped (Int_Base.neg (osizeof_pointed te1)) ev1 ev2
    | PlusA ->  V.add_untyped (Int_Base.one) ev1 ev2
    | MinusA -> V.add_untyped Int_Base.minus_one ev1 ev2
    | MinusPP ->
      let minus_val = V.add_untyped Int_Base.minus_one ev1 ev2 in
      begin
        try
          let size = Int_Base.project (sizeof_pointed te1) in
          let size = Int.div size Int.eight in
          if Int.is_one size then
            minus_val
          else
            let minus_val = Cvalue.V.project_ival minus_val in
            Cvalue.V.inject_ival (Ival.scale_div ~pos:true size minus_val)
        with
          | Int_Base.Error_Top
          | Cvalue.V.Not_based_on_null
          | Not_found ->
            V.join (V.topify_arith_origin ev1) (V.topify_arith_origin ev2)
      end
    | Mod -> V.c_rem ~with_alarms ev1 ev2
    | Div -> V.div ~with_alarms ev1 ev2
    | Mult -> V.arithmetic_function ~with_alarms "*" Ival.mul ev1 ev2
    | LOr ->
      assert false
                (* This code makes a strict evaluation: V.interp_boolean
                   ~contains_zero: (V.contains_zero ev1 &&
                   V.contains_zero ev2) ~contains_non_zero:
                   (V.contains_non_zero ev1 || V.contains_non_zero
                   ev2)*)

    | LAnd ->
      assert false
                (* This code makes a strict evaluation:
                   V.interp_boolean ~contains_zero: (V.contains_zero
                   ev1 || V.contains_zero ev2) ~contains_non_zero:
                   (V.contains_non_zero ev1 && V.contains_non_zero
                   ev2)*)

    | BXor ->
        V.oper_on_values ~with_alarms "^" Int.logxor ev1 ev2
    | BOr ->
        V.bitwise_or ~size:(bitsSizeOf te1) ev1 ev2
    | BAnd ->
      (try
         let size = bitsSizeOf te1 in
         let signed = is_signed_int_enum_pointer te1 in
         V.bitwise_and ~size ~signed ev1 ev2
       with SizeOfError _ ->
         V.join (V.topify_arith_origin ev1) (V.topify_arith_origin ev2))

    | Eq | Ne | Ge | Le | Gt | Lt ->
      let warn, ev1, ev2 = check_comparable op ev1 ev2 in
      if warn then CilE.warn_pointer_comparison with_alarms;
      if warn && Value_parameters.UndefinedPointerComparisonPropagateAll.get ()
      then V.zero_or_one
      else
        let signed = is_signed_int_enum_pointer (unrollType te1) in
        let f = match op with
          | Eq -> V.check_equal true
          | Ne -> V.check_equal false
          | Ge -> V.comparisons ">=" ~signed V.do_ge
          | Le -> V.comparisons "<=" ~signed V.do_le
          | Gt -> V.comparisons ">" ~signed V.do_gt
          | Lt -> V.comparisons "<" ~signed V.do_lt
          | _ -> assert false
        in
        f ev1 ev2
    | Shiftrt | Shiftlt ->
        begin
          let f = 
            if op = Shiftlt then V.shift_left else V.shift_right
          in
          try
            let size = Extlib.opt_map bitsSizeOf typ in
            f ~with_alarms ?size ev1 ev2
          with SizeOfError _ -> assert false          
        end