diff --git a/src/kernel_services/abstract_interp/ival.ml b/src/kernel_services/abstract_interp/ival.ml
index b9f8d8529c95358a14b00b53f6ee29139f433a23..2a04b50f4619a3a3570669a9371e1ff65dc18e92 100644
--- a/src/kernel_services/abstract_interp/ival.ml
+++ b/src/kernel_services/abstract_interp/ival.ml
@@ -92,6 +92,12 @@ type pre_set =
 type t =
   | Set of Int.t array
   | Float of Fval.t
+  (* [Top(min, max, rem, modulo)] represents the interval between
+     [min] and [max], congruent to [rem] modulo [modulo]. A value of
+     [None] for [min] (resp. [max]) represents -infinity
+     (resp. +infinity). [modulo] is > 0, and [0 <= rem < modulo].
+
+     Actual [Top] is thus represented by Top(None,None,Int.zero,Int.one) *)
   | Top of Int.t option * Int.t option * Int.t * Int.t
 (* Binary abstract operations do not model precisely float/integer operations.
    It is the responsibility of the callers to have two operands of the same
@@ -326,6 +332,15 @@ let project_float v =
     | Float f -> f
     | Top _ | Set _ -> assert false (* by hypothesis that it is a float *)
 
+let is_float = function
+  | Float _ -> true
+  | Top _ -> false
+  | Set _ as i -> equal zero i || equal bottom i
+
+let is_int = function
+  | Top _ | Set _ -> true
+  | Float _ -> false
+
 let in_interval x min max r modu =
   Int.equal (Int.e_rem x modu) r && min_le_elt min x && max_ge_elt max x
 
@@ -362,6 +377,14 @@ let project_int v = match v with
 | Set [| e |] -> e
 | _ -> raise Not_Singleton_Int
 
+let is_small_set = function
+  | Set _ -> true
+  | _ -> false
+
+let project_small_set = function
+  | Set a -> Some (Array.to_list a)
+  | _ -> None
+
 let cardinal v =
   match v with
     | Top (None,_,_,_) | Top (_,None,_,_) -> None
@@ -590,12 +613,8 @@ let min_and_max_float t =
   | Float f -> Fval.min_and_max f
   | _ -> assert false
 
-let is_float = function
-  | Float _ -> true
-  | Set _ | Top _ -> false
-
 let has_greater_min_bound t1 t2 =
-  if is_float t1 || is_float t2
+  if is_float t1 && is_float t2
   then Fval.has_greater_min_bound (project_float t1) (project_float t2)
   else
     let m1, _ = min_and_max t1 in
@@ -607,7 +626,7 @@ let has_greater_min_bound t1 t2 =
     | Some m1, Some m2 -> Int.compare m1 m2
 
 let has_smaller_max_bound t1 t2 =
-  if is_float t1 || is_float t2
+  if is_float t1 && is_float t2
   then Fval.has_smaller_max_bound (project_float t1) (project_float t2)
   else
     let _, m1 = min_and_max t1 in
diff --git a/src/kernel_services/abstract_interp/ival.mli b/src/kernel_services/abstract_interp/ival.mli
index a94f2aa8f8c32356edcef3dd7c3c67add75b029c..628066eea2104421a4fe3fe347b50e8c606b5055 100644
--- a/src/kernel_services/abstract_interp/ival.mli
+++ b/src/kernel_services/abstract_interp/ival.mli
@@ -26,16 +26,7 @@
 
 open Abstract_interp
 
-type t = private
-  | Set of Int.t array
-  | Float of Fval.t
-  (** [Top(min, max, rem, modulo)] represents the interval between
-      [min] and [max], congruent to [rem] modulo [modulo]. A value of
-      [None] for [min] (resp. [max]) represents -infinity
-      (resp. +infinity). [modulo] is > 0, and [0 <= rem < modulo].
-
-      Actual [Top] is thus represented by Top(None,None,Int.zero,Int.one) *)
-  | Top of Int.t option * Int.t option * Int.t * Int.t
+type t
 
 (** {2 General guidelines of this module}
 
@@ -68,6 +59,9 @@ include Lattice_type.Full_AI_Lattice_with_cardinality
 val is_bottom : t -> bool
 val overlaps: partial:bool -> size:Integer.t -> t -> t -> bool
 
+val is_float: t -> bool
+val is_int: t -> bool
+
 val add_int : t -> t -> t
 (** Addition of two integer (ie. not [Float]) ivals. *)
 val add_int_under : t -> t -> t
@@ -175,6 +169,10 @@ val project_int : t -> Integer.t
     (** @raise Not_Singleton_Int when the cardinal of the argument is not 1,
         or if it is not an integer. *)
 
+val is_small_set: t -> bool
+
+val project_small_set: t -> Integer.t list option
+
 val cardinal: t -> Integer.t option
 (** [cardinal v] returns [n] if [v] has finite cardinal [n], or [None] if
     the cardinal is not finite. *)
diff --git a/src/kernel_services/abstract_interp/offsetmap.ml b/src/kernel_services/abstract_interp/offsetmap.ml
index 506f4f18d86809dbf22a77df367a7c1aea3f7625..c6257bfd3d4398c06b6561cad8929c3e034f7ca2 100644
--- a/src/kernel_services/abstract_interp/offsetmap.ml
+++ b/src/kernel_services/abstract_interp/offsetmap.ml
@@ -2061,14 +2061,17 @@ let update_under ~validity ~exact ~offsets ~size v t =
   let paste_slice ~validity ~exact ~from:src ~size ~offsets dst =
     if Int.(equal size zero) then (* nothing to do *) `Value dst
     else
-      match offsets, src with
+      let size_ok =
+        Ival.is_singleton_int offsets
+        || let _, _, _, modu = Ival.min_max_r_mod offsets in size =~ modu
+      in
+      match src with
       (*Special case: [from] contains a single (aligned) binding [v], and [size]
         matches the periodicity of [offsets] and the size of [v]. In this case,
         it is more efficient to perform an interval update instead of an
         offsetmap copy. *)
-      | Ival.Top (_,_,_, offperiod), Node(_,_, Empty,_, Empty, vrem, vsize, v,_)
-        when Rel.is_zero vrem && size =~ offperiod &&
-             (size =~ vsize || V.is_isotropic v)
+      | Node (_,_, Empty,_, Empty, vrem, vsize, v,_)
+        when Rel.is_zero vrem && size_ok && (size =~ vsize || V.is_isotropic v)
         ->
         update ~validity ~exact ~offsets ~size v dst
       | _ ->
@@ -2708,15 +2711,11 @@ module Int_Intervals = struct
         in
         Intervals (curr_off', i, min, max)
       in
-      match ival with
-      | Ival.Top(None, _, _, _) | Ival.Top(_, None, _, _) | Ival.Float _ -> top
-      | Ival.Top(Some mn, Some mx, _r, _m) ->
-        aux_min_max mn mx
-      | Ival.Set(s) ->
-        if Array.length s > 0 then
-          aux_min_max s.(0) s.(Array.length s - 1)
-        else
-          bottom
+      try
+        match Ival.min_and_max ival with
+        | None, _ | _, None -> top
+        | Some min, Some max -> aux_min_max min max
+      with Error_Bottom -> bottom
     in
     Cache.merge from_ival_size_aux
 
@@ -2735,18 +2734,19 @@ module Int_Intervals = struct
     match size with
     | Int_Base.Top -> Bottom (* imprecise *)
     | Int_Base.Value size ->
-      match ival with
-      | Ival.Top(None, _, _, _) | Ival.Top(_, None, _, _) | Ival.Float _ ->
-        Bottom (* imprecise *)
-      | Ival.Set _ -> from_ival_size_over_cached ival size (* precise *)
-      | Ival.Top (Some min, Some start_max, _, _) ->
-        (* See if using [from_ival_size] would cause an approximation *)
-        let max = pred (start_max +~ size) in
-        let validity = Base.Known (min, max) in
-        let offsets = Tr_offset.trim_by_validity ival size validity in
-        if Int_Intervals_Map.update_aux_tr_offsets_approximates offsets size
-        then bottom (* imprecise *)
-        else from_ival_size_over_cached ival size (* precise *)
+      if Ival.is_small_set ival
+      then from_ival_size_over_cached ival size (* precise *)
+      else
+        match Ival.min_and_max ival with
+        | None, _ | _, None -> Bottom (* imprecise *)
+        | Some min, Some start_max ->
+          (* See if using [from_ival_size] would cause an approximation *)
+          let max = pred (start_max +~ size) in
+          let validity = Base.Known (min, max) in
+          let offsets = Tr_offset.trim_by_validity ival size validity in
+          if Int_Intervals_Map.update_aux_tr_offsets_approximates offsets size
+          then bottom (* imprecise *)
+          else from_ival_size_over_cached ival size (* precise *)
 
   let range_covers_whole_type typ itvs =
     match project_singleton itvs with
diff --git a/src/kernel_services/abstract_interp/tr_offset.ml b/src/kernel_services/abstract_interp/tr_offset.ml
index 1dff8c7d48b1c8cbcd94653452626b4025e4e7ed..379aa9ac52016c64693f87cad91e4739f801b7a6 100644
--- a/src/kernel_services/abstract_interp/tr_offset.ml
+++ b/src/kernel_services/abstract_interp/tr_offset.ml
@@ -47,10 +47,10 @@ let reduce_offset_by_validity origin ival size validity =
       let max_valid = Int.sub max (Int.pred size) in
       let valid_range = Ival.inject_range (Some min) (Some max_valid) in
       let reduced_ival = Ival.narrow ival valid_range in
-      match reduced_ival with
-      | Ival.Float _ -> assert false
-      | Ival.Set s -> if s = [||] then Invalid else Set (Array.to_list s)
-      | Ival.Top (min, max, _r, modu) ->
+      match Ival.project_small_set reduced_ival with
+      | Some l -> if l = [] then Invalid else Set l
+      | None ->
+        let min, max, _r, modu = Ival.min_max_r_mod reduced_ival in
         (* The bounds are finite thanks to the narrow with the valid range. *)
         let min = Extlib.the min and max = Extlib.the max in
         if Int.lt modu size
diff --git a/src/plugins/value/domains/cvalue/builtins_memory.ml b/src/plugins/value/domains/cvalue/builtins_memory.ml
index dac35d94de1cac889b51d9b42b3a004d8b712724..3039c1f9bbe17e922bb3f80b5a507fcba6211900 100644
--- a/src/plugins/value/domains/cvalue/builtins_memory.ml
+++ b/src/plugins/value/domains/cvalue/builtins_memory.ml
@@ -37,11 +37,11 @@ let frama_C_is_base_aligned state actuals =
     match actuals with
     | [_,x,_; _,y,_] ->
       let i = Cvalue.V.project_ival y in
-      begin match i with
-        | Ival.Set si ->
+      begin match Ival.project_small_set i with
+        | Some si ->
           Location_Bytes.fold_i
             (fun b _o () ->
-               Array.iter
+               List.iter
                  (fun int ->
                     if not (Base.is_aligned_by b int)
                     then raise Found_misaligned_base)
@@ -54,7 +54,7 @@ let frama_C_is_base_aligned state actuals =
             c_from = None;
             c_cacheable = Value_types.Cacheable;
           }
-        | _ -> raise Found_misaligned_base
+        | None -> raise Found_misaligned_base
       end
     | _ -> raise (Builtins.Invalid_nb_of_args 2)
   end
diff --git a/src/plugins/value/domains/cvalue/builtins_string.ml b/src/plugins/value/domains/cvalue/builtins_string.ml
index 3298ae3d4d48f3a32c20dcf44b40b49ba881d07c..e3ed961c845dea79c3c09c708f103da5d218ebb4 100644
--- a/src/plugins/value/domains/cvalue/builtins_string.ml
+++ b/src/plugins/value/domains/cvalue/builtins_string.ml
@@ -80,13 +80,14 @@ let read_exact_char ~offset ~from =
   let min = Integer.max (the_max_int from) (pos_min_int offset) in
   let offset = backward_comp_left Comp.Le offset min in
   let length = Ival.sub_int offset from in
-  match offset with
-  | Ival.Top (_min, _max, _rem, modu) ->
+  if not (Ival.is_singleton_int offset)
+  then
+    let _, _, _, modu = Ival.min_max_r_mod offset in
     let start_length = Integer.sub (pos_min_int offset) (pos_min_int from) in
     let max_length = Integer.max start_length modu in
     let length = backward_comp_left Comp.Lt length max_length in
     offset, length
-  | _ -> offset, length
+  else offset, length
 
 (* Checks if some limits are reached after a read at [offset]. In this case,
    adds these limits as possible lengths in [t], and adds null to [t]. *)
diff --git a/src/plugins/value/domains/gauges/gauges_domain.ml b/src/plugins/value/domains/gauges/gauges_domain.ml
index e45fc726212b250492260e4c551bc5c1bed3dea4..62ce07b51b98ab311330f1f79b1e12ba6348d26e 100644
--- a/src/plugins/value/domains/gauges/gauges_domain.ml
+++ b/src/plugins/value/domains/gauges/gauges_domain.ml
@@ -846,6 +846,11 @@ module G = struct
       with Cvalue.V.Not_based_on_null | Ival.Not_Singleton_Int ->
         raise Untranslatable
 
+    let has_variable_validity b =
+      match Base.validity b with
+      | Base.Variable _ -> true
+      | _ -> false
+
     (* Check that [v] is an integer, or a single pointer (invariant 2 of MV).
        Pointers to a single base with variable validity are also ruled out, as
        the base may become weak, making the pointer imprecise and thus breaking
@@ -853,11 +858,8 @@ module G = struct
     let sanitize_v v =
       try
         let b, i = Cvalue.V.find_lonely_key v in
-        let validity = Base.validity b in
-        match validity, i with
-        | Base.Variable _, _
-        | _, Ival.Float _ -> raise Untranslatable
-        | _, _ -> ()
+        if not (Ival.is_int i) || has_variable_validity b
+        then raise Untranslatable
       with Not_found -> raise Untranslatable
 
     let add (ct1, l1: t) (ct2, l2: t) : t =
diff --git a/src/plugins/value/domains/numerors/numerors_domain.ml b/src/plugins/value/domains/numerors/numerors_domain.ml
index 6295adc0eed64e7d4495b8c1dc62ed8aba6ec0cf..65fd9d13c246ced41dd04e82ecd8afa4bb67da8b 100644
--- a/src/plugins/value/domains/numerors/numerors_domain.ml
+++ b/src/plugins/value/domains/numerors/numerors_domain.ml
@@ -100,14 +100,13 @@ end
 let reduce_error cvalue error =
   try
     let ival = Cvalue.V.project_ival cvalue in
-    match ival with
-    | Ival.Float fval ->
-      begin
-        match Numerors_value.reduce fval error with
-        | `Value error -> cvalue, error
-        | `Bottom -> cvalue, error (* TODO: we should be able to reduce to bottom. *)
-      end
-    | _ -> cvalue, error
+    if Ival.is_float ival
+    then
+      let fval = Ival.project_float ival in
+      match Numerors_value.reduce fval error with
+      | `Value error -> cvalue, error
+      | `Bottom -> cvalue, error (* TODO: we should be able to reduce to bottom. *)
+    else cvalue, error
   with Cvalue.V.Not_based_on_null -> cvalue, error
 
 (* Reduction of the numerors value resulting from a cast from int to float type,
diff --git a/src/plugins/value/engine/abstractions.ml b/src/plugins/value/engine/abstractions.ml
index 4261513ad85956b5344086030abbb39c7cef4759..5e73c7d1374b9b9d76a5b9db7c43b7bd43eb2a60 100644
--- a/src/plugins/value/engine/abstractions.ml
+++ b/src/plugins/value/engine/abstractions.ml
@@ -337,12 +337,12 @@ let reduce_apron_itv cvalue ival =
   | Some ival ->
     try
       let ival' = Cvalue.V.project_ival cvalue in
-      (match ival' with
-       | Ival.Float _ -> raise Cvalue.V.Not_based_on_null
-       | _ -> ());
-      let reduced_ival = Ival.narrow ival ival' in
-      let cvalue = Cvalue.V.inject_ival reduced_ival in
-      cvalue, Some reduced_ival
+      if Ival.is_int ival'
+      then
+        let reduced_ival = Ival.narrow ival ival' in
+        let cvalue = Cvalue.V.inject_ival reduced_ival in
+        cvalue, Some reduced_ival
+      else cvalue, Some ival
     with Cvalue.V.Not_based_on_null -> cvalue, Some ival
 
 let () =
diff --git a/src/plugins/value/legacy/eval_op.ml b/src/plugins/value/legacy/eval_op.ml
index 03b3185c5769643921278386c05c1da5c31775e6..6fb7f3dc9fef2e5aa0c4d8e37aa62a70c3b87a43 100644
--- a/src/plugins/value/legacy/eval_op.ml
+++ b/src/plugins/value/legacy/eval_op.ml
@@ -161,14 +161,17 @@ let make_loc_contiguous loc =
     let base, offset =
       Locations.Location_Bits.find_lonely_key loc.Locations.loc
     in
-    match offset, loc.Locations.size with
-    | Ival.Top (Some min, Some max, _rem, modu), Int_Base.Value size
-      when Int.equal modu size ->
-      let size' = Int.add (Int.sub max min) modu in
-      let i = Ival.inject_singleton min in
-      let loc_bits = Locations.Location_Bits.inject base i in
-      Locations.make_loc loc_bits (Int_Base.inject size')
-    | _ -> loc
+    if Ival.is_small_set offset
+    then loc
+    else
+      let min, max, _rem, modu = Ival.min_max_r_mod offset in
+      match min, max, loc.Locations.size with
+      | Some min, Some max, Int_Base.Value size when Int.equal modu size ->
+        let size' = Int.add (Int.sub max min) modu in
+        let i = Ival.inject_singleton min in
+        let loc_bits = Locations.Location_Bits.inject base i in
+        Locations.make_loc loc_bits (Int_Base.inject size')
+      | _ -> loc
   with Not_found -> loc
 
 let apply_on_all_locs f loc state =
diff --git a/src/plugins/value/legacy/eval_terms.ml b/src/plugins/value/legacy/eval_terms.ml
index 089f3c93a5eadaca570d79802bec072a5d689b64..291139e5ccded4f527783880668e75e5d550b7ed 100644
--- a/src/plugins/value/legacy/eval_terms.ml
+++ b/src/plugins/value/legacy/eval_terms.ml
@@ -1145,7 +1145,7 @@ and eval_toffset ~alarm_mode env typ toffset =
         (* Note: scale_int_base would overapproximate when given a
            Float.  Should never happen. *)
         | Int_Base.Value f ->
-          (match offset with | Ival.Float _ -> assert false | _ -> ());
+          assert (Ival.is_int offset);
           Ival.scale f offset
       in
       Ival.add_int_under offset offsrem.eunder
diff --git a/src/plugins/value/utils/eval_typ.ml b/src/plugins/value/utils/eval_typ.ml
index d749568e9f5bb57c6b531f14ef9d693a76856e19..1b3c82b59e958d818386eea2880e65ba93811faf 100644
--- a/src/plugins/value/utils/eval_typ.ml
+++ b/src/plugins/value/utils/eval_typ.ml
@@ -52,18 +52,9 @@ let offsetmap_matches_type typ_lv o =
       try typ_matches (V.project_ival_bottom v)
       with V.Not_based_on_null -> true (* Do not mess with pointers *)
   in
-  let is_float = function
-    | Ival.Float _ -> true
-    | Ival.Top _ -> false
-    | Ival.Set _ as i -> Ival.(equal zero i || equal bottom i)
-  in
-  let is_int = function
-    | Ival.Top _ | Ival.Set _ -> true
-    | Ival.Float _ -> false
-  in
   match Cil.unrollType typ_lv with
-  | TFloat _ -> aux is_float
-  | TInt _ | TEnum _ | TPtr _ -> aux is_int
+  | TFloat _ -> aux Ival.is_float
+  | TInt _ | TEnum _ | TPtr _ -> aux Ival.is_int
   | _ -> true
 
 
diff --git a/src/plugins/value_types/cvalue.ml b/src/plugins/value_types/cvalue.ml
index 56124a5079b644189247e11c29afd8807e7ae581..66e5958a6e40179fc91c9fee4684a1366b319d8b 100644
--- a/src/plugins/value_types/cvalue.ml
+++ b/src/plugins/value_types/cvalue.ml
@@ -173,8 +173,8 @@ module V = struct
              type. Find a matching offset with potentially the wrong type *)
           find_match Bit_utils.MatchFirst, false
       in
-      match i with
-      | Ival.Set [|o|] ->
+      match Ival.project_small_set i with
+      | Some [o] ->
         (* One single offset. Use a short notation, and an even shorter one
            if we represent [&b] *)
         let o, ok = conv_offset o in
@@ -183,7 +183,7 @@ module V = struct
         else
           Format.fprintf fmt "@[%a%a%a@]"
             pretty_cast ok Base.pretty_addr b Printer.pp_offset o
-      | Ival.Set a -> (* Multiple offsets. We use a set notation *)
+      | Some a -> (* Multiple offsets. We use a set notation *)
         (* Catch NoOffset, which we would be printed as '{, [1], [2]}. Instead,
            we find a slightly deeper offset. We should never be in a different
            case from array/comp, as the other types cannot have multiple
@@ -199,7 +199,7 @@ module V = struct
           else o, ok
         in
         let arr_off, ok =
-          Array.fold_right
+          List.fold_right
             (fun o (l, ok)-> let o', ok' = conv_offset' o in o' :: l, ok && ok')
             a ([], true)
         in
@@ -208,10 +208,9 @@ module V = struct
           Base.pretty_addr b
           (Pretty_utils.pp_iter
              ~sep:",@ " List.iter Printer.pp_offset) arr_off
-      | Ival.Top _ ->
+      | None ->
         (* Too many offsets. Currently, we use the basic notation. *)
         pretty_base_offsets_default fmt b i
-      | Ival.Float _ -> assert false
     with
     (* Strange looking base, or no offset found. Use default printing *)
     | Base.Not_a_C_variable | Bit_utils.NoMatchingOffset ->