File: alpha.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 (395 lines) | stat: -rw-r--r-- 12,820 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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
(****************************************************************************)
(*                           the diy toolsuite                              *)
(*                                                                          *)
(* Jade Alglave, University College London, UK.                             *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France.                          *)
(*                                                                          *)
(* Copyright 2010-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.            *)
(****************************************************************************)

open Printf

module Make(O:MixOption.S)(A:Arch_tools.S) : sig

  val alpha : Name.t -> A.test (* avoid *) -> A.test (* alpha *) -> A.test
  val global : Name.t -> A.test (* avoid *) -> A.test (* alpha *) -> A.test
end =
struct

  open MiscParser

(****************)
(* Various sets *)
(****************)

  module OR = struct
    type t = A.reg
    let compare = A.reg_compare
  end

  let pp_rs rs = sprintf "{%s}" (A.RegSet.pp_str "," A.pp_reg rs)


  module RegMap = MyMap.Make(OR)

  module OPR = struct
    type t = int * A.reg
    let compare (p1,r1) (p2,r2) = match Misc.int_compare p1 p2 with
    | 0 -> A.reg_compare r1 r2
    | r -> r
  end

  module ProcRegSet = MySet.Make(OPR)
  module ProcRegMap = MyMap.Make(OPR)


(********************************)
(* Find all (integer) registers *)
(********************************)

  module Collect =  CollectRegs.Make(A)

  let collect_location loc regs = match loc with
  | A.Location_reg (p,r) -> ProcRegSet.add (p,r) regs
  | A.Location_global _ -> regs

  let collect_rloc = ConstrGen.fold_rloc collect_location

  let collect_state_atom (loc,_) = collect_location loc

  let collect_atom a regs =
    let open ConstrGen in
    match a with
    | LV (rloc,_) -> collect_rloc rloc regs
    | LL (loc1,loc2) ->  collect_location loc1 (collect_location loc2 regs)
    | FF (_,None,_) -> regs
    | FF (_,Some x,_) -> collect_location (A.Location_global x) regs

  let collect_state st = List.fold_right collect_state_atom st

  let collect_constr = ConstrGen.fold_constr collect_atom

  let collect_locs =
    let open LocationsItem in
    List.fold_right
      (fun i -> match i with
      | Loc (l,_) -> ConstrGen.fold_rloc collect_location l
      | Fault (_,None,_) -> Misc.identity
      | Fault (_,Some x,_) -> collect_location (A.Location_global x))

(***************************)
(* Alpha conversion proper *)
(***************************)


(* group according to proc *)
  let by_proc rs =
    ProcRegSet.fold
      (fun (p,r) m ->
        let rs = A.ProcMap.safe_find A.RegSet.empty p m in
        A.ProcMap.add p (A.RegSet.add r rs) m)
      rs A.ProcMap.empty

(* Lift reg -> reg map into a procreg -> procreg map *)
  let add_reg_map p m =
    RegMap.fold
      (fun r1 r2 -> ProcRegMap.add (p,r1) (A.Location_reg (p,r2)))
      m
(* alpha convert decorations *)

  let alpha_location f = function
    | A.Location_reg (p,r) -> f (p,r)
    | A.Location_global _ as loc -> loc

  let alpha_rloc f = ConstrGen.map_rloc (alpha_location f)

  let alpha_atom f a =
    let open ConstrGen in
    match a with
    | LV (rloc,v) -> LV (alpha_rloc f rloc,v)
    | LL (loc1,loc2) -> LL (alpha_location f loc1,alpha_location f loc2)
    | FF (_,None,_) -> a
    | FF (_,Some x,_) -> ignore (Constant.check_sym x) ; a

  let alpha_state_atom f (loc,x) = alpha_location f loc,x

  let alpha_state f = List.map (alpha_state_atom f)

  let alpha_locations f =
    let open LocationsItem in
    List.map
      (function
        | Loc (x,t) -> Loc (alpha_rloc f x,t)
        | Fault (_,None,_) as a -> a
        | Fault (_,Some x,_) as a -> ignore (Constant.check_sym x); a)

  let alpha_constr f = ConstrGen.map_constr (alpha_atom f)

(* alpha convert code, also returns the conversion map. *)
  let alpha_code ars rs ac c =
    (* Registers to avoid *)
    let ars = A.RegSet.union (Collect.collect_code ac) ars in
    (* Registers to convert *)
    let rs = A.RegSet.union (Collect.collect_code c) rs in
    let free = A.RegSet.diff (A.RegSet.of_list A.allowed_for_symb) ars in
    if O.verbose > 0 then begin
      eprintf "Free=%s\n" (pp_rs free)
    end ;
    let free = A.RegSet.elements free in
    let env,_ =
      A.RegSet.fold
        (fun r (env,free) -> match free with
        | [] -> Warn.user_error "not enough registers for alpha conversion"
        | f::free ->
            RegMap.add r f env,free)
        rs (RegMap.empty,free) in
    let c =
      List.map
        (A.pseudo_map
           (A.map_regs
              (fun r -> try RegMap.find r env with Not_found -> assert false)
              (fun _sr -> assert false)))
        c in
    c,env

  let rec alpha_prog ma mt apcs pcs = match apcs,pcs with
  | _,[] -> [],ProcRegMap.empty
  | [],((p,_,_) as id,c)::pcs ->
      let c,cm =
        alpha_code
          (A.ProcMap.safe_find A.RegSet.empty p ma)
          (A.ProcMap.safe_find A.RegSet.empty p mt)
          [] c in
      let pcs,m = alpha_prog ma mt [] pcs in
      (id,c)::pcs,add_reg_map p cm m
  | (_,ac)::apcs,((p,_,_) as id,c)::pcs ->
      let c,cm =
        alpha_code
          (A.ProcMap.safe_find A.RegSet.empty p ma)
          (A.ProcMap.safe_find A.RegSet.empty p mt)
          ac c in
      let pcs,m = alpha_prog ma mt apcs pcs in
      (id,c)::pcs,add_reg_map p cm m


(*********************************)
(* Again for global locations... *)
(*********************************)

  module Addr = struct
    open Constant

    let nolabel_value () = Warn.user_error "No label value for %s" Sys.argv.(0)
    let notag_value () = Warn.user_error "No tag value for %s" Sys.argv.(0)
    let nopte_value () = Warn.user_error "No pteval_t value for %s" Sys.argv.(0)
    let noinstr_value () = Warn.user_error "No instruction value for %s" Sys.argv.(0)

    let rec collect_value f v k = match v with
    | Symbolic (Virtual {name=s;_}|System ((PTE|PTE2),s)) -> f s k
    | Concrete _ -> k
    | ConcreteVector vs ->
       List.fold_left (fun k v -> collect_value f v k) k vs
    | ConcreteRecord vs ->
      StringMap.fold_values (collect_value f) vs k
    | Label _ -> nolabel_value ()
    | Tag _ -> notag_value ()
    | PteVal _ -> nopte_value ()
    | Instruction _ -> noinstr_value ()
    | Symbolic (Physical _|TagAddr _|System (TLB,_))
    | Frozen _
      -> assert false


    let rec map_value f v = match v with
    | Symbolic (Virtual sym) -> Symbolic (Virtual {sym with name=f sym.name; })
    | Symbolic (System (PTE,s)) ->  Symbolic (System (PTE,f s))
    | Symbolic (System (PTE2,s)) ->  Symbolic (System (PTE2,f s))
    | Concrete _ -> v
    | ConcreteVector vs ->
       ConcreteVector (List.map (map_value f) vs)
    | ConcreteRecord vs ->
       ConcreteRecord (StringMap.map (map_value f) vs)
    | Label _ -> nolabel_value ()
    | Tag _ -> notag_value ()
    | PteVal _ -> nopte_value ()
    | Instruction _ -> noinstr_value ()
    | Frozen _|Symbolic (Physical _|TagAddr _|System (TLB,_))
      -> assert false


    let collect_pseudo f =
      A.pseudo_fold
        (fun k ins -> A.fold_addrs (collect_value f) k ins)

    let map_pseudo f =
      A.pseudo_map (fun ins -> A.map_addrs (map_value f) ins)

    let collect_code f c k =
      List.fold_left (collect_pseudo f) k c

    let map_code f = List.map (map_pseudo f)

    let collect_prog f = List.fold_right (fun (_,c) -> collect_code f c)

    let map_prog f = List.map  (fun (p,c) -> p,map_code f c)

    let collect_location f loc k = match loc with
    | A.Location_reg _ -> k
    | A.Location_global v -> collect_value f v k

    let collect_rloc f  = ConstrGen.fold_rloc (collect_location f)

    let map_location f loc = match loc with
    | A.Location_reg _ -> loc
    | A.Location_global v ->
       let w = map_value f v in
       A.Location_global w

    let my_map_rloc f = ConstrGen.map_rloc (map_location f)

    let collect_state_atom f (loc,(_,v)) k =
      collect_location f loc (collect_value f v k)

    let collect_atom f a k =
      let open ConstrGen in
      match a with
      | LV (rloc,v) ->
          collect_rloc f rloc (collect_value f v k)
      | LL (loc1,loc2) ->
          collect_location f loc1 (collect_location f loc2 k)
      | FF (_,None,_) -> k
      | FF (_,Some x,_) ->
          collect_location f (A.Location_global x) k

    let map_state_atom f (loc,(t,v)) = map_location f loc,(t,map_value f v)

    let map_global f x = match map_location f (A.Location_global x) with
    | A.Location_global x -> x
    | _ -> assert false

    let map_atom f a =
      let open ConstrGen in
      match a with
      | LV (rloc,v) ->
          LV (my_map_rloc f rloc,map_value f v)
      | LL (loc1,loc2) ->
          LL (map_location f loc1,map_location f loc2)
      | FF(p,x,ft) -> FF (p,Misc.map_opt (map_global f) x,ft)

    let collect_state f = List.fold_right (collect_state_atom f)

    let map_state f = List.map (map_state_atom f)

    let collect_constr f = ConstrGen.fold_constr (collect_atom f)

    let map_constr f = ConstrGen.map_constr (map_atom f)

    let collect_locs f = LocationsItem.fold_locs (collect_location f)

    let map_locs f =
      let open LocationsItem in
      List.map
        (function
          | Loc (x,t) -> Loc (my_map_rloc f x,t)
          | Fault (p,x,ft)-> Fault (p,Misc.map_opt (map_global f) x,ft))

    module StringSet = MySet.Make(String)

    let collect_test t =
      let f = StringSet.add in
      let k = StringSet.empty in
      let k = collect_state f t.init k in
      let k = collect_locs f t.locations k in
      let k = collect_constr f t.condition k in
      collect_prog f t.prog k

    let all_addrs =
      StringSet.of_list
        ["x";"y";"z";"t";
         "a";"b";"c";"d";"e";"f";"g";"h";"i";"j";"k";"l";"m";"n";
         "o";"p";"q";"r";"s";"u";"v";"w";]

    module StringMap = MyMap.Make(String)

    let alpha_test env t =
      let f s =
        try StringMap.find s env
        with Not_found -> assert false in
      { t with
        init = map_state f t.init ;
        locations = map_locs f t.locations ;
        condition = map_constr f t.condition ;
        prog = map_prog f t.prog ; }

    let alpha avoid test =
      let ass = collect_test avoid
      and tss = collect_test test in
      if O.verbose > 0 then begin
        let pp_set = StringSet.pp_str "," Misc.identity in
        eprintf
          "avoid={%s}, source={%s}\n" (pp_set ass) (pp_set tss)
      end ;
      let free = StringSet.diff all_addrs ass in
      let free = StringSet.elements free in
      let env,_ =
        StringSet.fold
          (fun s (env,free) -> match free with
          | [] -> Warn.user_error "not enough names for alpha conversion"
          | f::free ->
              StringMap.add s f env,free)
          tss (StringMap.empty,free) in
      if O.verbose > 0 then begin
          let pp_map =
            StringMap.pp_str (fun x y -> sprintf "%s -> %s" x y) in
          eprintf "env={%s}\n" (pp_map env)
      end ;
      alpha_test env test

  end
  module T = TestHash.Make(A)

  let collect_decorations t =
    collect_constr t.condition
      (collect_locs t.locations (collect_state t.init ProcRegSet.empty))

  let alpha doc avoid test =
    (* Collect all integer registers from program decoration *)
    let apregs = collect_decorations avoid
    and pregs  = collect_decorations test in

    let prog,env =
      alpha_prog
        (by_proc apregs) (by_proc pregs) avoid.prog test.prog in
    let alpha_preg r =
      try ProcRegMap.find r env with Not_found -> assert false in
    let initial = alpha_state alpha_preg test.init
    and final = alpha_constr alpha_preg test.condition
    and locs = alpha_locations alpha_preg test.locations in
    let prog = T.refresh_labels "X" prog in
    let r =
      { test with
        prog = prog; init = initial;
        condition = final; locations = locs; } in
    let r = Addr.alpha avoid r in
    if O.verbose > 0 then begin
      let module D = Dumper.Make(A) in
      D.dump stderr doc r
    end ;
    r

  let global doc avoid test =
    let r = Addr.alpha avoid test in
    if O.verbose > 0 then begin
      let module D = Dumper.Make(A) in
      D.dump stderr doc r
    end ;
    r

end