let eval_expr ~with_alarms state expr = match expr.enode with
  | BinOp ((MinusA | MinusPP | Eq | Ne | Ge | Le | Gt | Lt as op),e1,e2,_) ->
      let state, ev1 = !Db.Value.eval_expr_with_state ~with_alarms state e1 in
      let state, ev2 = !Db.Value.eval_expr_with_state ~with_alarms state e2 in
      CilE.set_syntactic_context (CilE.SyBinOp (op,e1,e2));
      begin
        match unrollType (typeOf e1) with
        | TFloat _ ->
            state,Cvalue_type.V.top
        | TInt _ | TPtr (_, _) | _ (* Enum ? *) ->
            let compute_diff acc =
              let lv1 = !Db.Value.find_lv_plus ~with_alarms state e1 in
              let lv2 = !Db.Value.find_lv_plus ~with_alarms state e2 in
              List.fold_left
                (fun acc (lv1, offs1)  ->
                   let loc1 = !Db.Value.lval_to_loc_state state lv1 in
                   List.fold_left
                     (fun acc (lv2, offs2)  ->
                        let loc2 = !Db.Value.lval_to_loc_state state lv2 in
                        try
                          let new_v =
                            V.location_shift
                              (Ival.sub offs1 offs2)
                              (Relations_type.Model.compute_diff
                                  state loc1 loc2)
                          in
                          assert (V.is_included new_v acc);
                          new_v
                        with Relations_type.Use_Main_Memory -> acc)
                     acc
                     lv2)
                acc
                lv1
            in
            match op with
            | MinusA -> state,compute_diff Cvalue_type.V.top
            | MinusPP ->
                let minus_val = compute_diff Cvalue_type.V.top in
                let r =
                  try
                          let size = Int_Base.project
                            (sizeof_pointed(Cil.typeOf e1))
                          in
                          let size = Int.div size Int.eight in
                          if Int.is_one size then
                            minus_val
                          else
                            let minus_val =
                              Cvalue_type.V.project_ival minus_val
                            in
                            Cvalue_type.V.inject_ival
                              (Ival.scale_div ~pos:true size minus_val)
                        with
                          Int_Base.Error_Top
                        | Cvalue_type.V.Not_based_on_null
                        | Not_found ->
                            V.join
                              (V.topify_arith_origin ev1)
                              (V.topify_arith_origin ev2)
                in
                state, r
            | Eq | Ne | Ge | Le | Gt | Lt ->
                let r =
                  let warn, ev1, ev2 = check_comparable ev1 ev2 in
                  if warn
                  then begin
                      CilE.warn_pointer_comparison with_alarms;
                    end;
                  if warn && Value_parameters.UndefinedPointerComparisonPropagateAll.get ()
                  then V.zero_or_one
                  else
                    let f = match op with
                    | Eq -> V.check_equal true
                    | Ne -> V.check_equal false
                    | Ge -> V.comparisons ">=" V.do_ge
                    | Le -> V.comparisons "<=" V.do_le
                    | Gt -> V.comparisons ">" V.do_gt
                    | Lt -> V.comparisons "<" V.do_lt
                    | _ -> assert false
                    in
                    let diff = compute_diff V.top in
                    let result = f diff V.singleton_zero in
                    if V.cardinal_zero_or_one result
                    then result
                    else f ev1 ev2
                in
                state, r

            | _ -> state,Cvalue_type.V.top

      end
  | _ -> state,Cvalue_type.V.top