File: final.ml

package info (click to toggle)
herdtools7 7.58-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,732 kB
  • sloc: ml: 128,583; ansic: 3,827; makefile: 670; python: 407; sh: 212; awk: 14
file content (341 lines) | stat: -rw-r--r-- 11,366 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
(****************************************************************************)
(*                           the diy toolsuite                              *)
(*                                                                          *)
(* Jade Alglave, University College London, UK.                             *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France.                          *)
(*                                                                          *)
(* Copyright 2014-present Institut National de Recherche en Informatique et *)
(* en Automatique and the authors. All rights reserved.                     *)
(*                                                                          *)
(* This software is governed by the CeCILL-B license under French law and   *)
(* abiding by the rules of distribution of free software. You can use,      *)
(* modify and/ or redistribute the software under the terms of the CeCILL-B *)
(* license as circulated by CEA, CNRS and INRIA at the following URL        *)
(* "http://www.cecill.info". We also give a copy in LICENSE.txt.            *)
(****************************************************************************)

module type Config = sig
  val verbose : int
  val cond : Config.cond
  val optcond : bool
  val hexa : bool
  val variant : Variant_gen.t -> bool
end

module Make : functor (O:Config) -> functor (C:ArchRun.S) ->
  sig

(* During compilation of cycle, final state is a
   pair eventmap * fenv, where
    + fenv associates locations to final values;
    + eventmap maps one event to the register
      written by the node. This is useful only
      for simulating execution in `-cond unicond` mode *)

    type vset
    type fenv = (C.A.location * vset) list
    type eventmap = C.A.location C.C.EventMap.t

(* Add an observation to fenv *)
    val add_final_v :
        Code.proc -> C.A.arch_reg -> IntSet.t -> fenv -> fenv
    val add_final_pte :
        Code.proc -> C.A.arch_reg -> C.A.PteVal.t -> fenv -> fenv
    val add_final_loc :
        Code.proc -> C.A.arch_reg -> string -> fenv -> fenv
    val cons_int :   C.A.location -> int -> fenv -> fenv
    val cons_vec : C.A.location -> int array -> fenv -> fenv
    val cons_pteval :   C.A.location -> C.A.PteVal.t -> fenv -> fenv
    val cons_int_set :  (C.A.location * IntSet.t) -> fenv -> fenv
    val add_int_sets : fenv -> (C.A.location * IntSet.t) list -> fenv

(* Standard function to record an association from register
   to expected value:
   Call is `add_final get_friends proc reg node (map,fenv)`,
   where:
     + get_friends returns the "friends of register",
       friends are registers whose expected value is
       identical. Those may stem from instructions that
       write into several registers.
     + proc is a thread identifier.
     + reg is a register option, when None nothing happens.
     + node is the current node.
     + (map,env) is the old final structure.
*)
    val add_final :
      (C.A.arch_reg -> C.A.arch_reg list) ->
      Code.proc -> C.A.arch_reg option -> C.C.node ->
      eventmap * fenv -> eventmap * fenv

    type faults = (Proc.t * StringSet.t) list
    type final

    val check : fenv -> faults -> final
    val observe : fenv -> faults -> final
    val run : C.C.event list list -> C.A.location C.C.EventMap.t -> faults -> final

    val dump_final : out_channel ->  final -> unit

(* Complement init environemt *)
    val extract_ptes : fenv -> C.A.location list

  end = functor (O:Config) -> functor (C:ArchRun.S) ->
  struct

    let do_kvm = Variant_gen.is_kvm O.variant

    type v = I of int | S of string | P of C.A.PteVal.t
    let pte_def = P (C.A.PteVal.default "*")
    let () = ignore pte_def

    let looks_like_array = function
      | S s -> String.length s > 0 && s.[0] = '{'
      | _ -> false


    module VSet =
      MySet.Make
        (struct
          type t = v

          let compare v1 v2 = match v1,v2 with
          | I i1,I i2 -> compare i1 i2
          | S s1,S s2 -> String.compare s1 s2
          | P p1,P p2 -> C.A.PteVal.compare p1 p2
          | ((P _|S _),I _)
          | (P _,S _)
            -> -1
          | (I _,(S _|P _))
          | (S _,P _)
            -> +1
        end)
    type vset = VSet.t
    type fenv = (C.A.location * vset) list
    type eventmap = C.A.location C.C.EventMap.t

    let show_in_cond =
      if O.optcond then
        let valid_edge m =
          let e = m.C.C.edge in
          let open C.E in
          match e.C.E.edge with
          | Rf _ | Fr _ | Ws _ | Hat
          | Back _|Leave _ -> true
          | Rmw rmw -> C.A.show_rmw_reg rmw
          | Po _ | Fenced _ | Dp _ ->
              begin match C.E.loc_sd e with
              | Code.Same -> true
              | Code.Diff -> false
              end
          |Insert _|Store|Node _ -> false
          | Id -> assert false in
        (fun n ->
          let p = C.C.find_non_pseudo_prev n.C.C.prev in
          valid_edge p || valid_edge n)
      else
        (fun _ -> true)

    let intset2vset is =
      IntSet.fold (fun v k -> VSet.add (I v) k) is VSet.empty

    let add_final_v p r v finals = (C.A.of_reg p r,intset2vset v)::finals

    let add_final_pte p r v finals = (C.A.of_reg p r,VSet.singleton (P v))::finals

    let add_final_loc p r v finals =
      let loc = C.A.of_reg p r in
      (loc,VSet.singleton (S v))::finals

    let cons_int loc i fs = (loc,VSet.singleton (I i))::fs

    let cons_vec loc t fs =
      let vec = Code.add_vector O.hexa (Array.to_list t) in
      (loc,VSet.singleton (S vec))::fs

    let cons_pteval loc p fs = (loc,VSet.singleton (P p))::fs

    let cons_int_set (l,is) fs = (l,intset2vset is)::fs

    let add_int_sets fs f =
      fs@List.map (fun (l,is) -> l,intset2vset is) f

    let prev_value = fun v -> v-1

    let add_final get_friends p o n finals = match o with
    | Some r ->
        let m,fs = finals in
        let evt = n.C.C.evt in
        let bank = evt.C.C.bank in
        let v = match evt.C.C.dir with
        | Some Code.R ->
            begin match bank with
            | Code.CapaTag
            | Code.CapaSeal
            | Code.Ord
            | Code.Pair
            | Code.Instr
              ->
                Some (I evt.C.C.v)
            | Code.VecReg _->
               let v0 =
                 match evt.C.C.vecreg with
                 | [] -> assert false
                 | v0::_ -> v0 in
                let vec = Code.add_vector O.hexa v0 in
                Some (S vec)
            | Code.Tag ->
                Some (S (Code.add_tag (Code.as_data evt.C.C.loc) evt.C.C.v))
            | Code.Pte ->
                Some (P evt.C.C.pte)
            end
        | Some Code.W ->
           assert (evt.C.C.bank = Code.Ord || evt.C.C.bank = Code.CapaSeal) ;
           Some (I (prev_value evt.C.C.v))
        | None|Some Code.J -> None in
        if show_in_cond n then match v with
        | Some v ->
           let add_to_fs r v fs =
             (C.A.of_reg p r,VSet.singleton v)::fs in
           let vs =
             match bank with
             | Code.VecReg _ ->
                begin match evt.C.C.vecreg with
                | _::vs ->
                   List.map (fun v -> S (Code.add_vector O.hexa v)) vs
                | _ -> assert false
                end
             | _ -> [] in
           let m = C.C.EventMap.add n.C.C.evt (C.A.of_reg p r) m
           and fs =
             try
               add_to_fs r v
                 (List.fold_right2 add_to_fs (get_friends r) vs fs)
             with Invalid_argument _ ->
               Printf.eprintf "Something wrong on %s\n"
                  (C.C.str_node n) ;
               assert false in
           m,fs
        | None -> finals
        else finals
    | None -> finals

    type faults = (Proc.t * StringSet.t) list

    type cond_final =
      | Exists of fenv
      | Forall of (C.A.location * Code.v) list list
      | Locations of C.A.location list

    type final = cond_final * faults

    module Run = Run_gen.Make(O)(C)

    let check f flts = Exists f,flts
    let observe f flts = Locations (List.map fst f),flts
    let run evts m flts = Forall (Run.run evts m),flts

(* Dumping *)
    open Printf

    let dump_val = function
      | I i ->
          if O.hexa then sprintf "0x%x" i
          else sprintf "%i" i
      | S s -> s
      | P p -> C.A.PteVal.pp p

    let dump_tag = function
      | I i -> i
      | _ -> Warn.fatal "Tags can only be of type integer"

    let dump_atom r v = match Misc.tr_atag (C.A.pp_location r) with
        | Some s -> sprintf "[tag(%s)]=%s" s (Code.add_tag "" (dump_tag v))
        | None ->
           let pp_loc =
             if looks_like_array v then C.A.pp_location
             else C.A.pp_location_brk in
           sprintf "%s=%s" (pp_loc r) (dump_val v)

    let dump_state fs =
      String.concat " /\\ "
        (List.map
           (fun (r,vs) ->
             match VSet.as_singleton vs with
             | Some v ->
                 dump_atom r v
             | None ->
                 let pp =
                   VSet.pp_str " \\/ "
                     (fun v -> dump_atom r v)
                     vs in
                 sprintf "(%s)" pp)
           fs)

    let dump_one_flt p x =  sprintf "fault (%s,%s)" (Proc.pp p) x

    let dump_flt sep (p,xs) = StringSet.pp_str sep (dump_one_flt p) xs

    let dump_flts =
      if do_kvm then fun _ ->   ""
      else fun flts ->
        let pp = List.map (dump_flt " \\/ ") flts in
        let pp = String.concat " \\/ " pp in
        match flts with
        | [] -> ""
        | [_,xs] when StringSet.is_singleton xs -> "~" ^ pp
        | _ -> sprintf "~(%s)" pp

    let dump_locations chan = function
      | [] -> ()
      | locs -> fprintf chan "locations [%s]\n" (String.concat " " locs)

    let dump_final chan (f,flts) =
      let loc_flts =
        if do_kvm then
          List.fold_right
            (fun (p,xs) ->
              StringSet.fold
                (fun x k -> sprintf "%s;" (dump_one_flt p x)::k)
                xs)
            flts []
        else [] in
      match f with
      | Exists fs ->
          dump_locations chan loc_flts ;
          let ppfs = dump_state fs
          and ppflts = dump_flts flts in
          let cc = match ppfs,ppflts with
          | "","" -> ""
          | "",_ -> ppflts
          | _,"" -> sprintf "(%s)" ppfs
          | _,_ -> sprintf "(%s) /\\ %s" ppfs ppflts in
          if cc <> "" then
            fprintf chan "%sexists %s\n" (if !Config.neg then "~" else "") cc
      | Forall ffs ->
          dump_locations chan loc_flts ;
          fprintf chan "forall\n" ;
          fprintf chan "%s%s\n" (Run.dump_cond ffs)
            (match dump_flts flts with
            | "" -> ""
            | pp -> " /\\ "^pp)
      | Locations locs ->
          dump_locations chan
            (List.fold_right
               (fun loc k -> sprintf "%s;" (C.A.pp_location loc)::k)
               locs loc_flts) ;
          begin match dump_flts flts with
          | "" -> ()
          | pp -> if not do_kvm then fprintf chan "forall %s\n" pp
          end

(* Extract ptes *)
    let extract_ptes =
      List.fold_left
        (fun k (loc,vset) ->
          if
            VSet.exists (function | P _ -> true | (I _|S _) -> false)
              vset then
            loc::k
          else k)
        []
  end