let select_lval_rw set mark ~rd ~wr ~scope ~eval kf ki_opt=
  assert (Db.Value.is_computed ());
   let zone_option lval_str =
    if Datatype.String.Set.is_empty lval_str
    then None
    else
      let zone =
        Datatype.String.Set.fold
          (fun lval_str acc ->
             let lval_term = !Db.Properties.Interp.lval kf scope lval_str in
             let lval = !Db.Properties.Interp.term_lval_to_lval ~result:None lval_term in
             let loc = !Db.Value.lval_to_loc ~with_alarms:CilE.warn_none_mode (Kstmt eval) lval in
             let zone = Locations.valid_enumerate_bits loc
             in Locations.Zone.join zone acc)
          lval_str Locations.Zone.bottom
      in SlicingParameters.debug ~level:3
           "select_lval_rw %a zone=%a"
           Kernel_function.pretty_name kf
           Locations.Zone.pretty zone;
        Some zone
   in
   let zone_rd_opt = zone_option rd in
   let zone_wr_opt = zone_option wr
   in match zone_rd_opt, zone_wr_opt with
     | NoneNone -> set
     | (_, _) as zone_option_rw ->
         let ac = ref set in
         let select_rw_from_stmt kf ki =
           let rd_zone_opt, wr_zone_opt = Kinstr.is_rw_zone zone_option_rw ki in
           let select_zone ~before zone_opt =
             match zone_opt with
               | None -> !ac
               | Some zone ->
                   SlicingParameters.debug ~level:3
                     "select_lval_rw sid=%d before=%b zone=%a"
                     ki.sid before Locations.Zone.pretty zone;
                   select_stmt_zone !ac mark zone ~before ki kf ;
           in
             ac := select_zone ~before:true rd_zone_opt ;
             ac := select_zone ~before:false wr_zone_opt
         in (match ki_opt with
               | Some ki -> select_rw_from_stmt kf ki
               | None ->
                   Globals.Functions.iter
                     (fun kf ->
                        if !Db.Value.is_called kf then
                          if Kernel_function.is_definition kf
                          then (* Called function with source code: just looks at its stmt *)
                            Kinstr.iter_from_func (select_rw_from_stmt kf) kf
                          else begin (* Called function without source code: looks at its effect *)
                            let select_inter_zone fsel zone_opt zone =
                              match zone_opt with
                                | None -> ()
                                | Some zone_requested ->
                                    (* Format.printf "@\nselect_lval_rw zone_req=%a zone=%a@."
                                       Locations.Zone.pretty zone_requested
                                       Locations.Zone.pretty zone; *)

                                    if Locations.Zone.intersects zone_requested zone
                                    then let inter = Locations.Zone.narrow zone_requested zone
                                    in fsel inter
                                    else () in
                            let select_wr outputs =
                              ac := select_entry_point_and_some_inputs_outputs !ac ~mark kf
                                ~return:false ~outputs ~inputs:Locations.Zone.bottom
                            and select_rd inputs =
                              ac := select_entry_point_and_some_inputs_outputs !ac ~mark kf
                                ~return:false ~inputs ~outputs:Locations.Zone.bottom

                            in
                              assert (!Db.Value.is_called kf) ; (* otherwise [!Db.Outputs.get_external kf] gives weird results *)
                              select_inter_zone select_wr zone_wr_opt (!Db.Outputs.get_external kf) ;
                              select_inter_zone select_rd zone_rd_opt (!Db.Inputs.get_external kf)
                          end
                     ));
           !ac