diff --git a/src/plugins/value/Eva.mli b/src/plugins/value/Eva.mli
index 97761d74c2583992f4fcd2a463e8380e860766c4..f44c2e4c112623521a6b4404f2c007e29b3e91b0 100644
--- a/src/plugins/value/Eva.mli
+++ b/src/plugins/value/Eva.mli
@@ -88,12 +88,15 @@ module Eva_annotations: sig
     | UnrollFull (** Unroll amount defined by -eva-default-loop-unroll. *)
 
   type split_kind = Static | Dynamic
+  type split_term =
+    | Expression of Cil_types.exp
+    | Predicate of Cil_types.predicate
 
   (** Split/merge annotations for value partitioning.  *)
   type flow_annotation =
-    | FlowSplit of Cil_types.term * split_kind
+    | FlowSplit of split_term * split_kind
     (** Split states according to a term. *)
-    | FlowMerge of Cil_types.term
+    | FlowMerge of split_term
     (** Merge states separated by a previous split. *)
 
   val add_slevel_annot : emitter:Emitter.t -> loc:Cil_types.location ->
diff --git a/src/plugins/value/partitioning/partition.ml b/src/plugins/value/partitioning/partition.ml
index 2325162fd0ccd2e1557bc5b3fbf8e5c43fd4d68a..47019da338d0c85d1e28c6cde7ae52915863e020 100644
--- a/src/plugins/value/partitioning/partition.ml
+++ b/src/plugins/value/partitioning/partition.ml
@@ -53,7 +53,25 @@ let new_rationing ~limit ~merge = { current = ref 0; limit; merge }
 
 (* --- Keys --- *)
 
-module ExpMap = Cil_datatype.ExpStructEq.Map
+type split_term = Eva_annotations.split_term =
+  | Expression of Cil_types.exp
+  | Predicate of Cil_types.predicate
+
+module SplitTerm = struct
+  type t = split_term
+  let compare x y =
+    match x, y with
+    | Expression e1, Expression e2 -> Cil_datatype.ExpStructEq.compare e1 e2
+    | Predicate p1, Predicate p2 -> Logic_utils.compare_predicate p1 p2
+    | Expression _, Predicate _ -> 1
+    | Predicate _, Expression _ -> -1
+
+  let pretty fmt = function
+    | Expression e -> Printer.pp_exp fmt e
+    | Predicate p -> Printer.pp_predicate fmt p
+end
+
+module SplitMap = Map.Make (SplitTerm)
 module IntPair = Datatype.Pair (Datatype.Int) (Datatype.Int)
 module LoopList = Datatype.List (IntPair)
 module BranchList = Datatype.List (Datatype.Int)
@@ -85,8 +103,8 @@ type key = {
   ration_stamp : stamp;
   branches : branch list;
   loops : (int * int) list; (* current iteration / max unrolling *)
-  static_split : (Integer.t*split_monitor) ExpMap.t; (* exp->value*monitor *)
-  dynamic_split : (Integer.t*split_monitor) ExpMap.t; (* exp->value*monitor *)
+  static_split : (Integer.t*split_monitor) SplitMap.t; (* exp->value*monitor *)
+  dynamic_split : (Integer.t*split_monitor) SplitMap.t; (* exp->value*monitor *)
 }
 
 module Key =
@@ -98,8 +116,8 @@ struct
     ration_stamp = None;
     branches = [];
     loops = [];
-    static_split = ExpMap.empty;
-    dynamic_split = ExpMap.empty;
+    static_split = SplitMap.empty;
+    dynamic_split = SplitMap.empty;
   }
 
   let compare k1 k2 =
@@ -111,8 +129,8 @@ struct
     in
     Option.compare IntPair.compare k1.ration_stamp k2.ration_stamp
     <?> (LoopList.compare, k1.loops, k2.loops)
-    <?> (ExpMap.compare compare_split, k1.static_split, k2.static_split)
-    <?> (ExpMap.compare compare_split, k1.dynamic_split, k2.dynamic_split)
+    <?> (SplitMap.compare compare_split, k1.static_split, k2.static_split)
+    <?> (SplitMap.compare compare_split, k1.dynamic_split, k2.dynamic_split)
     <?> (BranchList.compare, k1.branches, k2.branches)
 
   let pretty fmt key =
@@ -129,11 +147,11 @@ struct
       fmt
       key.loops;
     Pretty_utils.pp_list ~pre:"{@[" ~sep:" ;@ " ~suf:"@]}"
-      (fun fmt (e,(i,_m)) -> Format.fprintf fmt "%a:%a"
-          Cil_printer.pp_exp e
+      (fun fmt (t,(i,_m)) -> Format.fprintf fmt "%a:%a"
+          SplitTerm.pretty t
           (Integer.pretty ~hexa:false) i)
       fmt
-      (ExpMap.bindings key.static_split @ ExpMap.bindings key.dynamic_split)
+      (SplitMap.bindings key.static_split @ SplitMap.bindings key.dynamic_split)
 
   let exceed_rationing key = key.ration_stamp = None
 end
@@ -175,8 +193,8 @@ type action =
   | Branch of branch * int
   | Ration of rationing
   | Restrict of Cil_types.exp * Integer.t list
-  | Split of Cil_types.exp * split_kind * split_monitor
-  | Merge of Cil_types.exp
+  | Split of split_term * split_kind * split_monitor
+  | Merge of split_term
   | Update_dynamic_splits
 
 exception InvalidAction
@@ -328,6 +346,26 @@ struct
     | Failure _ ->
       fail ~exp "this partitioning parameter is too big"
 
+  let split_by_predicate state predicate =
+    let env =
+      let states = function _ -> Abstract.Dom.top in
+      Abstract_domain.{ states; result = None }
+    in
+    let source = fst (predicate.Cil_types.pred_loc) in
+    let aux positive =
+      Abstract.Dom.reduce_by_predicate env state predicate positive
+      >>-: fun state' ->
+      let x = Abstract.Dom.evaluate_predicate env state' predicate in
+      if x == Unknown
+      then
+        Value_parameters.warning ~source ~once:true
+          "failing to learn perfectly from split predicate";
+      if Abstract.Dom.equal state' state then raise Operation_failed;
+      let value = if positive then Integer.one else Integer.zero in
+      value, state'
+    in
+    Bottom.all [ aux true; aux false ]
+
   (* --- Applying partitioning actions onto flows --------------------------- *)
 
   let stamp_by_value = match Abstract.Val.get Main_values.CVal.key with
@@ -352,10 +390,10 @@ struct
             None
           end
 
-  let split_state ~monitor (kind : split_kind) (exp : Cil_types.exp)
+  let split_state ~monitor (kind : split_kind) (term : split_term)
       (key : key) (state : state) : (key * state) list =
     try
-      let add value map = ExpMap.add exp (value, monitor) map in
+      let add value map = SplitMap.add term (value, monitor) map in
       let update_key (v,x) =
         let k =
           match kind with
@@ -364,13 +402,18 @@ struct
         in
         (k,x)
       in
-      List.map update_key (split_by_value ~monitor state exp)
+      let states =
+        match term with
+        | Expression exp -> split_by_value ~monitor state exp
+        | Predicate pred -> split_by_predicate state pred
+      in
+      List.map update_key states
     with Operation_failed ->
       [(key,state)]
 
-  let split ~monitor (kind : split_kind) (exp : Cil_types.exp) (p : t) =
+  let split ~monitor (kind : split_kind) (term : split_term) (p : t) =
     let add_split acc (key,state) =
-      split_state ~monitor kind exp key state @ acc
+      split_state ~monitor kind term key state @ acc
     in
     List.fold_left add_split [] p
 
@@ -385,7 +428,7 @@ struct
         List.fold_left resplit [] l
       in
       (* Foreach exp in original state: split *)
-      ExpMap.fold update_exp key.dynamic_split [(key,state)] @ acc
+      SplitMap.fold update_exp key.dynamic_split [(key,state)] @ acc
     in
     List.fold_left update_state [] p
 
@@ -472,8 +515,8 @@ struct
           { k with ration_stamp = stamp_by_value expr expected_values s}
 
         | Merge exp -> fun k _x ->
-          { k with static_split = ExpMap.remove exp k.static_split;
-                   dynamic_split = ExpMap.remove exp k.dynamic_split }
+          { k with static_split = SplitMap.remove exp k.static_split;
+                   dynamic_split = SplitMap.remove exp k.dynamic_split }
       in
       map_keys transfer p
 
diff --git a/src/plugins/value/partitioning/partition.mli b/src/plugins/value/partitioning/partition.mli
index 1b773efe9871741fa80dccd87cd5d8043a3f3472..fe3dc9f303f8332f8009fdf419dc10f6676509c1 100644
--- a/src/plugins/value/partitioning/partition.mli
+++ b/src/plugins/value/partitioning/partition.mli
@@ -94,6 +94,11 @@ type unroll_limit =
       states are then split or merged accordingly. *)
 type split_kind = Eva_annotations.split_kind = Static | Dynamic
 
+(** Splits can be performed according to a C expression or an ACSL predicate. *)
+type split_term = Eva_annotations.split_term =
+  | Expression of Cil_types.exp
+  | Predicate of Cil_types.predicate
+
 (** Split monitor: prevents splits from generating too many states. *)
 type split_monitor
 
@@ -137,7 +142,7 @@ type action =
       – all other states are joined together.
       Previous rationing is erased and replaced by this new stamping.
       Implementation of the option -eva-split-return. *)
-  | Split of Cil_types.exp * split_kind * split_monitor
+  | Split of split_term * split_kind * split_monitor
   (** [Split (exp, kind, monitor)] tries to separate states such as the [exp]
       evaluates to a singleton value in each state in the flow. If necessary and
       possible, splits states into multiple states. States in which the [exp]
@@ -145,7 +150,7 @@ type action =
       if [exp] evaluates to more than [limit] values, [limit] being the split
       limit of the [monitor]. A same monitor can be used for successive splits
       on different flows. *)
-  | Merge of Cil_types.exp
+  | Merge of split_term
   (** Forgets the split of an expression: states that were kept separate only
       by the split of this expression will be joined together. *)
   | Update_dynamic_splits
diff --git a/src/plugins/value/partitioning/partitioning_parameters.ml b/src/plugins/value/partitioning/partitioning_parameters.ml
index b3609a90cc6a44a40b5f9c9ba369a3426c9b0cef..519e2fc02290aabc32213050079494afe4a23073 100644
--- a/src/plugins/value/partitioning/partitioning_parameters.ml
+++ b/src/plugins/value/partitioning/partitioning_parameters.ml
@@ -116,7 +116,8 @@ struct
       try
         let vi = Globals.Vars.find_from_astinfo name VGlobal in
         let monitor = Partition.new_monitor ~split_limit in
-        Partition.Split (Cil.evar vi, Partition.Dynamic, monitor) :: l
+        let expr = Partition.Expression (Cil.evar vi) in
+        Partition.Split (expr, Partition.Dynamic, monitor) :: l
       with Not_found ->
         warn ~current:false "cannot find the global variable %s for value \
                              partitioning; ignoring" name;
@@ -130,8 +131,8 @@ struct
         let monitor = Partition.new_monitor ~split_limit in
         let action =
           match t with
-          | FlowSplit (t, kind) -> Partition.Split (term_to_exp t, kind, monitor)
-          | FlowMerge t -> Partition.Merge (term_to_exp t)
+          | FlowSplit (t, kind) -> Partition.Split (t, kind, monitor)
+          | FlowMerge t -> Partition.Merge t
         in
         action :: acc
       with
diff --git a/src/plugins/value/utils/eva_annotations.ml b/src/plugins/value/utils/eva_annotations.ml
index adaf06945a43d70cf60b9961a85b01753885ebf3..075cc5773385e4b7f315d9e719f79a1fbb4f081e 100644
--- a/src/plugins/value/utils/eva_annotations.ml
+++ b/src/plugins/value/utils/eva_annotations.ml
@@ -34,10 +34,13 @@ type unroll_annotation =
   | UnrollFull
 
 type split_kind = Static | Dynamic
+type split_term =
+  | Expression of Cil_types.exp
+  | Predicate of Cil_types.predicate
 
 type flow_annotation =
-  | FlowSplit of term * split_kind
-  | FlowMerge of term
+  | FlowSplit of split_term * split_kind
+  | FlowMerge of split_term
 
 type taint_annotation = Cil_types.term list
 
@@ -155,26 +158,6 @@ module Slevel = Register (struct
       | SlevelFull -> Format.pp_print_string fmt "full"
   end)
 
-module SimpleTermAnnotation =
-struct
-  type t = term
-
-  let parse ~typing_context = function
-    | [t] ->
-      let open Logic_typing in
-      typing_context.type_term typing_context typing_context.pre_state t
-    | _ -> raise Parse_error
-
-  let export t =
-    Ext_terms [t]
-
-  let import = function
-    | Ext_terms [t] -> t
-    | _ -> assert false
-
-  let print = Printer.pp_term
-end
-
 module ListTermAnnotation =
 struct
   type t = term list
@@ -222,20 +205,64 @@ module Unroll = Register (struct
       | UnrollAmount t -> Printer.pp_term fmt t
   end)
 
+module SplitTermAnnotation =
+struct
+  type t = split_term
+
+  let term_to_exp = !Db.Properties.Interp.term_to_exp ~result:None
+
+  let parse ~typing_context = function
+    | [t] ->
+      begin
+        let open Logic_typing in
+        let exception No_term in
+        try
+          let error _loc _fmt = raise No_term in
+          let typing_context = { typing_context with error } in
+          let term =
+            typing_context.type_term typing_context typing_context.pre_state t
+          in
+          Expression (term_to_exp term)
+        with
+        | No_term ->
+          Predicate
+            (typing_context.type_predicate
+               typing_context typing_context.pre_state t)
+        | Db.Properties.Interp.No_conversion ->
+          Kernel.warning ~wkey:Kernel.wkey_annot_error ~once:true ~current:true
+            "split/merge expressions must be valid expressions; ignoring";
+          raise Parse_error
+      end
+    | _ -> raise Parse_error
+
+  let export = function
+    | Expression expr -> Ext_terms [ Logic_utils.expr_to_term expr ]
+    | Predicate pred -> Ext_preds [pred]
+
+  let import = function
+    | Ext_terms [term] -> Expression (term_to_exp term)
+    | Ext_preds [pred] -> Predicate pred
+    | _ -> assert false
+
+  let print fmt = function
+    | Expression expr -> Printer.pp_exp fmt expr
+    | Predicate pred -> Printer.pp_predicate fmt pred
+end
+
 module Split = Register (struct
-    include SimpleTermAnnotation
+    include SplitTermAnnotation
     let name = "split"
     let is_loop_annot = false
   end)
 
 module Merge = Register (struct
-    include SimpleTermAnnotation
+    include SplitTermAnnotation
     let name = "merge"
     let is_loop_annot = false
   end)
 
 module DynamicSplit = Register (struct
-    include SimpleTermAnnotation
+    include SplitTermAnnotation
     let name = "dynamic_split"
     let is_loop_annot = false
   end)
diff --git a/src/plugins/value/utils/eva_annotations.mli b/src/plugins/value/utils/eva_annotations.mli
index 629f8ffe5adb5b1116e5f1214be649bbfb04ca6d..dd7d580bdb463911ea778c79cce32184008d0859 100644
--- a/src/plugins/value/utils/eva_annotations.mli
+++ b/src/plugins/value/utils/eva_annotations.mli
@@ -40,9 +40,13 @@ type unroll_annotation =
 
 type split_kind = Static | Dynamic
 
+type split_term =
+  | Expression of Cil_types.exp
+  | Predicate of Cil_types.predicate
+
 type flow_annotation =
-  | FlowSplit of Cil_types.term * split_kind
-  | FlowMerge of Cil_types.term
+  | FlowSplit of split_term * split_kind
+  | FlowMerge of split_term
 
 type taint_annotation = Cil_types.term list