File: modelUtils.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 (232 lines) | stat: -rw-r--r-- 8,828 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
(****************************************************************************)
(*                           the diy toolsuite                              *)
(*                                                                          *)
(* Jade Alglave, University College London, UK.                             *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France.                          *)
(*                                                                          *)
(* Copyright 2013-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 Make(O:Model.Config) (S:SemExtra.S) = struct
  module E = S.E
  module U = MemUtils.Make(S)

  let memtag = O.variant Variant.MemTag
  let morello = O.variant Variant.Morello
  let do_deps = O.variant Variant.Deps
  let iico_ctrl_as_dep = match S.A.arch with
  | `AArch64 -> true
  | _ -> false
  and kvm = O.variant Variant.VMSA

  let is_mem_kvm =
    if kvm then E.is_mem_physical
    else E.is_mem

(*******************************************)
(* Complete re-computation of dependencies *)
(*******************************************)
  let seq_or_id r1 r2 = S.union (S.seq r1 r2) r2

  let evt_relevant x =
    E.is_mem x || E.is_commit x || E.is_barrier x
    || E.is_additional_mem x

  let is_mem_load_total e =
    (is_mem_kvm e && E.is_load e) || E.is_additional_mem_load e
  let is_load_total e = E.is_load e || E.is_additional_mem_load e

  let make_procrels_deps conc =
    let iico =
      E.EventRel.union
        conc.S.str.E.intra_causality_data
        (if iico_ctrl_as_dep then
          conc.S.str.E.intra_causality_control
        else
          E.EventRel.empty)
    and rf_regs = U.make_rf_regs conc in
    let iico_regs =
      E.EventRel.restrict_rel
        (fun  e1 e2  -> not (evt_relevant e1 || evt_relevant e2)) iico in
    let dd_inside = S.tr (E.EventRel.union rf_regs iico_regs) in
    let success =
      if O.variant Variant.Success then
        S.seq
          (E.EventRel.restrict_domain
             (fun e1 -> E.EventSet.mem e1 conc.S.str.E.success_ports)
             dd_inside)
          (E.EventRel.restrict_codomain E.is_mem iico)
      else E.EventRel.empty in

    let e =  E.EventRel.empty in
    let addr = e and data = e and ctrl = e and depend = e
    and ctrlisync = e and data_commit = e in
    let rf = U.make_rf conc in
    { S.addr; data; ctrl; depend; ctrlisync; data_commit;
      success; rf; tst=e;},iico,dd_inside

  let make_procrels_nodeps is_isync conc =
    let pr0,iico,dd_inside = make_procrels_deps conc in
    let is_data_port =
      let data_ports = conc.S.str.E.data_ports in
      fun e -> E.EventSet.mem e data_ports in
    let iico_rmw =
      E.EventRel.inter conc.S.atomic_load_store
        conc.S.str.E.intra_causality_data in
    let iico_from_mem_load = (* First step of dependencies *)
      E.EventRel.restrict_domain is_mem_load_total iico in
    let dd_pre =
(* Most dependencies start with a mem load, a few with a mem store + ctrl
   RISCV *)
      S.seq
        (E.EventRel.union
           (E.EventRel.restrict_domain E.is_mem_store
              conc.S.str.E.intra_causality_control)
           iico_from_mem_load)
        dd_inside in
    let data_dep =
(* Data deps are (1) dd to commits (2) data deps to stores *)
      let last_data =
        E.EventRel.restrict_rel
          (fun e1 e2 ->
            E.is_commit e2 ||
            (is_mem_kvm e2 && E.is_store e2 && is_data_port e1)) iico in
      S.union3
        (E.EventRel.restrict_domain is_mem_load_total last_data)
        (S.seq dd_pre last_data)
        (iico_rmw) (* Internal data dep of RMW's *)
    and addr_dep =
(* Address deps are (1) dd to loads, (2) non-data deps to stores, (3) extra
   abstract "memory" events (such as lock, unlock, etc. that have an address
   port *)
      let last_addr =
        E.EventRel.restrict_rel
          (fun e1 e2 ->
            (is_mem_kvm e2 &&
             (E.is_load e2 ||
             (E.is_store e2 && not (is_data_port e1)))) ||
            E.is_additional_mem e2)
           (* Patch: a better solution would be a direct iico from read address register to access *)
          (if memtag || kvm || morello then E.EventRel.transitive_closure iico else iico) in
      S.union
        (E.EventRel.restrict_domain is_mem_load_total last_addr)
        (S.seq dd_pre last_addr) in
    let po = U.po_iico conc.S.str in
    let ctrl_one = (* For bcc: from commit to event by po *)
      S.restrict E.is_bcc evt_relevant po
    and ctrl_two = (* For predicated instruction from commit to event by iico *)
      S.restrict E.is_pred evt_relevant (U.iico conc.S.str)
    and ctrl_three = (* For structured if from event to event by instruction control *)
      S.restrict is_load_total evt_relevant conc.S.str.E.control in
    let ctrl =
      E.EventRel.union3 ctrl_one ctrl_two ctrl_three in
    let ctrl_dep =
      (* All dependencies, including to reg loads *)
      let dd = S.union3 dd_pre addr_dep data_dep in
      let control_from_load =
        E.EventRel.restrict_domain E.is_load conc.S.str.E.control in
      let ddplus =
        S.seq iico_from_mem_load
          (S.tr (S.union dd_inside control_from_load)) in
      S.restrict
        (fun e -> is_mem_load_total e || E.is_mem_store e)
        evt_relevant
        (S.union (S.seq dd ctrl) (seq_or_id ddplus control_from_load)) in
    let po =
      S.restrict evt_relevant evt_relevant po in
    let data_commit =
      E.EventRel.restrict_codomain E.is_commit data_dep in
    let data_dep =  E.EventRel.restrict_codomain E.is_mem data_dep in
    let ctrlisync =
      try
        let r1 = S.restrict is_mem_load_total is_isync ctrl_dep
        and r2 = S.restrict is_isync E.is_mem po in
        S.seq r1 r2
      with Misc.NoIsync -> S.E.EventRel.empty in
    { pr0 with S.addr=addr_dep; data=data_dep; ctrl=ctrl_dep; depend=dd_pre;
      ctrlisync; data_commit;}

  let make_procrels =
    if do_deps then
      fun _ conc -> let pr,_,_ = make_procrels_deps conc in pr
    else
      make_procrels_nodeps

  let pp_procrels pp_isync pr =
    let pp =  ["data",pr.S.data; "addr",pr.S.addr;] in
    match pp_isync with
    | None -> ("ctrl",pr.S.ctrl)::pp
    | Some isync ->
        let ctrl =  E.EventRel.diff pr.S.ctrl pr.S.ctrlisync in
        (Printf.sprintf "ctrl%s" isync,pr.S.ctrlisync)::
        ("ctrl",ctrl)::pp


(***************************)
(* A few factorized checks *)
(***************************)
  open Model

  let pp test conc legend vb_pp =
    let module PP = Pretty.Make(S) in
    Printf.eprintf "%s\n%!" legend ;
    PP.show_legend test  legend conc vb_pp

  let pp_failure test conc legend vb_pp =
    if O.debug then pp test conc legend vb_pp

(* Through *)
  let check_through =
    match O.through with
    | ThroughAll|ThroughInvalid -> fun _ -> true
    | ThroughNone -> fun ok -> ok

(* Uniproc *)
  let check_uniproc test conc rf fr co =
    let rel = S.unions [fr;rf;co;conc.S.pos] in
    let r = E.EventRel.is_acyclic rel in
    if S.O.optace = OptAce.True then assert r ;
    let r = let open Model in
    match O.through with
    | ThroughNone|ThroughInvalid ->  r
    | ThroughAll -> true in
    if not r then
      pp_failure
        test conc
        (Printf.sprintf "%s: Uniproc violation" test.Test_herd.name.Name.name)
        [("co",S.rt co); ("fr",fr); ("pos",S.rt conc.S.pos)] ;
    r

  let check_atom test conc fr co =
    let ws = U.collect_mem_stores conc.S.str in
    let r =
      E.EventRel.for_all
        (fun (r,w) ->
          assert (E.same_location r w) ;
          let loc =
            match E.location_of w with
            | Some loc -> loc | None  -> assert false in
          let ws = U.LocEnv.find loc ws in
          not
            (List.exists
               (fun w' ->
                 E.proc_of r <> E.proc_of w' &&
                 E.EventRel.mem (r,w') fr &&
                 E.EventRel.mem (w',w) co)
               ws))
        conc.S.atomic_load_store in
    let r = check_through r in
    if not r then
      pp_failure
        test conc
        (Printf.sprintf "%s: Atomicity violation" test.Test_herd.name.Name.name)
        ["co",S.rt co; "fr",fr;"r*/w*",conc.S.atomic_load_store;];
    r
end