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 -> 
                state,let minus_val = compute_diff Cvalue_type.V.top in
                ( try
                    let size = Int_Base.project
                      (sizeof_pointed(Cil.typeOf e1))
                    in
                    let size = Int.div size (Int.of_int 8) in
                    if Int.equal size Int.one then
                      minus_val
                    else 
                      let minus_val = Cvalue_type.V.find_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))
            | Eq | Ne | Ge | Le | Gt | Lt ->
                state,let ev1, ev2 = check_comparable ~with_alarms ev1 ev2 in
                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
            | _ -> state,Cvalue_type.V.top
                
      end
  | _ -> state,Cvalue_type.V.top