Skip to content

Commit 9ff1745

Browse files
committed
[litmus2desc] WIP: add litmus2desc
1 parent 967de3e commit 9ff1745

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3019
-0
lines changed

tools/litmus2desc/.ocamlformat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
disable = false

tools/litmus2desc/bin/dune

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(executable
2+
(name main)
3+
(public_name litmus2desc)
4+
(flags
5+
(:standard -w -42))
6+
(libraries herdtools unix litmus2desc))

tools/litmus2desc/bin/main.ml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module Top = Litmus2desc.Explainer
2+
3+
let () =
4+
let file_path = ref None in
5+
let usage = "Usage: litmus2desc [options] FILE" in
6+
7+
let libdir = ref None in
8+
let describe_regs = ref false in
9+
let latex = ref false in
10+
let options =
11+
[
12+
( "-set-libdir",
13+
Arg.String (fun s -> libdir := Some s),
14+
"<path> set libdir" );
15+
( "--describe-regs",
16+
Arg.Unit (fun () -> describe_regs := true),
17+
"enable descriptions of register events. Default = disabled." );
18+
( "--latex",
19+
Arg.Unit (fun () -> latex := true),
20+
"Output test description as LaTeX. Default = disabled." );
21+
]
22+
in
23+
let process_arg arg =
24+
match !file_path with
25+
| None -> file_path := Some arg
26+
| Some _ ->
27+
prerr_endline "Only one FILE argument is allowed";
28+
Arg.usage options usage;
29+
exit 2
30+
in
31+
32+
Arg.parse options process_arg usage;
33+
34+
let file_path =
35+
match !file_path with
36+
| Some p -> p
37+
| None ->
38+
prerr_endline "Missing FILE argument.";
39+
Arg.usage options usage;
40+
exit 2
41+
in
42+
43+
let config =
44+
Top.{ libdir = !libdir; describe_regs = !describe_regs; latex = !latex }
45+
in
46+
print_endline (Top.explain_test_path ~config file_path)

tools/litmus2desc/lib/EdgeGraph.ml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
type vertex = int
2+
type edge = { label : string; source : vertex; target : vertex }
3+
type t = { vertices : IntSet.t; succ : edge list IntMap.t }
4+
5+
let make vertices edges =
6+
let vertices =
7+
List.fold_left (fun acc v -> IntSet.add v acc) IntSet.empty vertices
8+
in
9+
let vertices =
10+
List.fold_left
11+
(fun acc edge -> acc |> IntSet.add edge.source |> IntSet.add edge.target)
12+
vertices edges
13+
in
14+
let succ =
15+
List.fold_right
16+
(fun edge acc ->
17+
IntMap.update edge.source
18+
(function
19+
| None -> Some [ edge ] | Some edges -> Some (edge :: edges))
20+
acc)
21+
edges IntMap.empty
22+
in
23+
{ vertices; succ }
24+
25+
let outgoing_edges (g : t) (v : vertex) : edge list =
26+
match IntMap.find_opt v g.succ with Some edges -> edges | None -> []
27+
28+
let iter_simple_paths ~(src : vertex) ~(dst : vertex)
29+
~(pred : src:vertex -> tgt:vertex -> string -> bool)
30+
~(f : vertex list -> unit) (g : t) : unit =
31+
if not (IntSet.mem src g.vertices && IntSet.mem dst g.vertices) then ()
32+
else
33+
let rec dfs visited path v =
34+
if v = dst then f (List.rev (v :: path))
35+
else
36+
outgoing_edges g v
37+
|> List.iter (fun edge ->
38+
let next = edge.target in
39+
if
40+
(not (IntSet.mem next visited))
41+
&& pred ~src:edge.source ~tgt:next edge.label
42+
then
43+
let visited' = IntSet.add next visited in
44+
dfs visited' (v :: path) next)
45+
in
46+
dfs (IntSet.singleton src) [] src
47+
48+
let simple_paths_iter ~(src : int) ~(dst : int)
49+
~(pred : src:vertex -> tgt:vertex -> string -> bool) (g : t) :
50+
int list Util.Iter.t =
51+
fun f -> iter_simple_paths ~f ~src ~dst ~pred g
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type t
2+
type vertex = int
3+
type edge = { label : string; source : vertex; target : vertex }
4+
5+
val make : vertex list -> edge list -> t
6+
7+
val simple_paths_iter :
8+
src:vertex ->
9+
dst:vertex ->
10+
pred:(src:vertex -> tgt:vertex -> string -> bool) ->
11+
t ->
12+
vertex list Util.Iter.t

tools/litmus2desc/lib/JsonGraph.ml

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
(* JSON graph decoders for herd's JSON output. *)
2+
3+
module Decoders = struct
4+
module D = Decoders_yojson.Basic.Decode
5+
open D.Infix
6+
open Execution
7+
8+
let d_dir : dir D.decoder =
9+
let* s = D.string in
10+
match s with
11+
| "R" -> D.succeed R
12+
| "W" -> D.succeed W
13+
| _ -> D.fail "invalid direction"
14+
15+
let d_event_ref : event_ref D.decoder =
16+
let+ eiid = D.field "eiid" D.int in
17+
{ eiid }
18+
19+
let d_rel_edge : rel_edge D.decoder =
20+
let* src = D.field "src" d_event_ref in
21+
let+ tgt = D.field "tgt" d_event_ref in
22+
{ src; tgt }
23+
24+
let d_location : location D.decoder =
25+
let* ty = D.field "type" D.string in
26+
match ty with
27+
| "reg" ->
28+
let* proc = D.field "proc" D.int in
29+
let+ reg_pretty = D.field "reg_pretty" D.string in
30+
Reg { proc; reg_pretty }
31+
| "global" ->
32+
let+ global_pretty = D.field "global_pretty" D.string in
33+
Global global_pretty
34+
| _ -> D.fail "unknown location type"
35+
36+
let d_cst : cst D.decoder =
37+
let* ty = D.field "type" D.string in
38+
match ty with
39+
| "concrete" ->
40+
let+ scalar_pretty = D.field "scalar_pretty" D.string in
41+
Concrete { scalar_pretty }
42+
| "symbolic" ->
43+
let+ symbol_pretty = D.field "symbol_pretty" D.string in
44+
Symbolic { symbol_pretty }
45+
| "pteval" ->
46+
let* pteval_pretty = D.field "pteval_pretty" D.string in
47+
let+ as_physical = D.maybe (D.field "as_physical" D.string) in
48+
Pteval { pteval_pretty; as_physical }
49+
| _ -> D.fail "unknown constant value type"
50+
51+
let d_value : value D.decoder =
52+
let* ty = D.field "type" D.string in
53+
match ty with
54+
| "var" ->
55+
let+ v = D.field "var" D.int in
56+
Var v
57+
| "val" ->
58+
let d_val_pretty =
59+
let+ vp = D.field "val_pretty" D.string in
60+
Val_pretty vp
61+
in
62+
let d_val =
63+
let+ v = D.field "val" d_cst in
64+
Val v
65+
in
66+
D.one_of [ ("val_pretty", d_val_pretty); ("val", d_val) ]
67+
| _ -> D.fail "unknown value type"
68+
69+
let d_mem_action : mem_action D.decoder =
70+
let+ dir = D.field "dir" d_dir
71+
and+ loc = D.field "loc" d_location
72+
and+ value = D.field "value" d_value
73+
and+ is_implicit = D.field_opt_or ~default:false "is_implicit" D.bool
74+
and+ is_atomic = D.field_opt_or ~default:false "is_atomic" D.bool in
75+
{ dir; loc; value; is_implicit; is_atomic }
76+
77+
let d_reg_action : reg_action D.decoder =
78+
let+ dir = D.field "dir" d_dir
79+
and+ loc = D.field "loc" d_location
80+
and+ value = D.field "value" d_value in
81+
{ dir; loc; value }
82+
83+
let d_action : action D.decoder =
84+
let* ty = D.field "type" D.string in
85+
match ty with
86+
| "mem" ->
87+
let+ c = d_mem_action in
88+
Memory c
89+
| "reg" ->
90+
let+ c = d_reg_action in
91+
Register c
92+
| "barrier" ->
93+
let+ barrier_pretty = D.field "barrier_pretty" D.string in
94+
Barrier { barrier_pretty }
95+
| "commit" ->
96+
let+ commit = D.field "commit" D.string in
97+
Commit { commit }
98+
| "fault" -> D.succeed Fault
99+
| _ -> D.fail "unknown action type"
100+
101+
let d_iiid : iiid D.decoder =
102+
let d_id =
103+
let* proc = D.field "proc" D.int in
104+
let* poi = D.field "poi" D.int in
105+
let+ inst_pretty = D.field "inst_pretty" D.string in
106+
Index { proc; poi; inst_pretty }
107+
in
108+
let d_init_spurious =
109+
let* s = D.string in
110+
match s with
111+
| "init" -> D.succeed Init
112+
| "spurious" -> D.succeed Spurious
113+
| _ -> D.fail "not a simple iiid string"
114+
in
115+
D.one_of [ ("init_spurious", d_init_spurious); ("id", d_id) ]
116+
117+
let d_event : event D.decoder =
118+
let* act = D.field "act" d_action in
119+
let* eiid = D.field "eiid" D.int in
120+
let+ iiid = D.field "iiid" d_iiid in
121+
{ act; eiid; iiid }
122+
123+
open struct
124+
open RFMap
125+
126+
let d_rfmap_src : src D.decoder =
127+
let* ty = D.field "type" D.string in
128+
match ty with
129+
| "final" ->
130+
let+ loc = D.field "loc" d_location in
131+
Final loc
132+
| "load" ->
133+
let+ event = D.field "event" d_event_ref in
134+
Load event
135+
| _ -> D.fail "unknown rfmap src"
136+
137+
let d_rfmap_tgt : tgt D.decoder =
138+
let* ty = D.field "type" D.string in
139+
match ty with
140+
| "init" -> D.succeed Init
141+
| "store" ->
142+
let+ event = D.field "event" d_event_ref in
143+
Store event
144+
| _ -> D.fail "unknown rfmap tgt"
145+
146+
let d_rfmap_edge : edge D.decoder =
147+
let* src = D.field "src" d_rfmap_src in
148+
let+ tgt = D.field "tgt" d_rfmap_tgt in
149+
{ src; tgt }
150+
end
151+
152+
let d_viewed_before : viewed_before D.decoder =
153+
D.key_value_pairs (D.list d_rel_edge)
154+
155+
let decode : t D.decoder =
156+
let* events = D.field "events" (D.list d_event) in
157+
let* iico_data = D.field "iico_data" (D.list d_rel_edge) in
158+
let* iico_ctrl = D.field "iico_ctrl" (D.list d_rel_edge) in
159+
let* speculated = D.field "speculated" (D.list d_event_ref) in
160+
let* rfmap = D.field "rfmap" (D.list d_rfmap_edge) in
161+
let* viewed_before = D.field "viewed_before" d_viewed_before in
162+
let+ visible_po = D.maybe (D.field "visible_po" (D.list d_rel_edge)) in
163+
{
164+
events;
165+
iico_data;
166+
iico_ctrl;
167+
speculated;
168+
rfmap;
169+
viewed_before;
170+
visible_po;
171+
}
172+
173+
let decode_list : t list D.decoder = D.list decode
174+
175+
let decode_string (s : string) : (t list, string) result =
176+
D.decode_string decode_list s |> Result.map_error D.string_of_error
177+
end
178+
179+
let decode_json_string = Decoders.decode_string
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
val decode_json_string : string -> (Execution.t list, string) result

0 commit comments

Comments
 (0)