Project

General

Profile

Download (7.83 KB) Statistics
| Branch: | Tag: | Revision:
1
(* ----------------------------------------------------------------------------
2
 * SchedMCore - A MultiCore Scheduling Framework
3
 * Copyright (C) 2009-2013, ONERA, Toulouse, FRANCE - LIFL, Lille, FRANCE
4
 * Copyright (C) 2012-2013, INPT, Toulouse, FRANCE
5
 *
6
 * This file is part of Prelude
7
 *
8
 * Prelude is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation ; either version 2 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * Prelude is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY ; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this program ; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
 * USA
22
 *---------------------------------------------------------------------------- *)
23

    
24
open Utils
25
open LustreSpec
26
open Corelang
27
open Graph
28
open Causality
29

    
30
(* Computes the last dependency
31
*)
32

    
33
(* Computes the death table of [node] wrt dep graph [g] and topological [sort].
34
   The death table is a mapping: ident -> Set(ident) such that:
35
   death x is the set of local variables which get dead (i.e. unused) 
36
   after x is evaluated, but were until live.
37
let death_table node g sort =
38
  let death = Hashtbl.create 23 in
39
  let sort  = ref (List.rev sort) in
40
  let buried  = ref ISet.empty in
41
  begin
42
    buried := ExprDep.node_memory_variables node;
43
    buried := List.fold_left (fun dead (v : var_decl) -> ISet.add v.var_id dead) !buried node.node_outputs;
44
    (* We could also try to reuse input variables, due to C parameter copying semantics *)
45
    buried := List.fold_left (fun dead (v : var_decl) -> ISet.add v.var_id dead) !buried node.node_inputs;
46
    while (!sort <> [])
47
    do
48
      let head = List.hd !sort in
49
      let dead = IdentDepGraph.fold_succ
50
	(fun tgt dead -> if not (ExprDep.is_instance_var tgt || ISet.mem tgt !buried) then ISet.add tgt dead else dead)
51
	g head ISet.empty in
52
      buried := ISet.union !buried dead;
53
      Hashtbl.add death head dead;
54
      sort := List.tl !sort
55
    done;
56
    IdentDepGraph.clear g;
57
    death
58
  end
59
*)
60

    
61

    
62
(* computes the cone of influence of a given [var] wrt a dependency graph [g].
63
*)
64
let cone_of_influence g var =
65
 (*Format.printf "coi: %s@." var;*)
66
 let frontier = ref (ISet.add var ISet.empty) in
67
 let coi = ref ISet.empty in
68
 while not (ISet.is_empty !frontier)
69
 do
70
   let head = ISet.min_elt !frontier in
71
   (*Format.printf "head: %s@." head;*)
72
   frontier := ISet.remove head !frontier;
73
   if ExprDep.is_read_var head then coi := ISet.add (ExprDep.undo_read_var head) !coi;
74
   List.iter (fun s -> frontier := ISet.add s !frontier) (IdentDepGraph.succ g head);
75
 done;
76
 !coi
77

    
78
let compute_unused n g =
79
  let inputs = ExprDep.node_input_variables n in
80
  let mems = ExprDep.node_memory_variables n in
81
  let outputs = ExprDep.node_output_variables n in
82
  ISet.fold
83
    (fun var unused -> ISet.diff unused (cone_of_influence g var))
84
    (ISet.union outputs mems)
85
    (ISet.union inputs mems) 
86

    
87
(* Computes the set of (input and) output and mem variables of [node].
88
   We try to reuse input variables, due to C parameter copying semantics. *)
89
let node_non_locals node =
90
 List.fold_left (fun non_loc v -> ISet.add v.var_id non_loc) (ExprDep.node_memory_variables node) node.node_outputs
91

    
92
(* Recursively removes useless local variables,
93
   i.e. variables in [non_locals] that are current roots of the dep graph [g] *)
94
let remove_local_roots non_locals g =
95
  let rem = ref true in
96
  let roots = ref ISet.empty in
97
  while !rem
98
  do
99
    rem := false;
100
    let local_roots = List.filter (fun v -> not (ISet.mem v non_locals)) (graph_roots g) in
101
    if local_roots <> [] then
102
      begin
103
	rem := true;
104
	List.iter (IdentDepGraph.remove_vertex g) local_roots;
105
	roots := List.fold_left (fun roots v -> if ExprDep.is_instance_var v then roots else ISet.add v roots) !roots local_roots 
106
      end
107
  done;
108
  !roots
109

    
110
(* Computes the death table of [node] wrt dep graph [g] and topological [sort].
111
   The death table is a mapping: ident -> Set(ident) such that:
112
   death x is the set of local variables which get dead (i.e. unused) 
113
   before x is evaluated, but were until live.
114
   If death x is not defined, then x is useless.
115
*)
116
let death_table node g sort =
117
  let non_locals = node_non_locals node in
118
  let death = Hashtbl.create 23 in
119
  let sort  = ref sort in
120
  begin
121
    while (!sort <> [])
122
    do
123
      let head = List.hd !sort in
124
      (* If current var is not already dead, i.e. useless *)
125
      if IdentDepGraph.mem_vertex g head then
126
	begin
127
	  IdentDepGraph.iter_succ (IdentDepGraph.remove_edge g head) g head;
128
	  let dead = remove_local_roots non_locals g in
129
	  Hashtbl.add death head dead
130
	end;
131
      sort := List.tl !sort
132
    done;
133
    IdentDepGraph.clear g;
134
    death
135
  end
136

    
137
let pp_death_table fmt death =
138
  begin
139
    Format.fprintf fmt "{ /* death table */@.";
140
    Hashtbl.iter (fun s t -> Format.fprintf fmt "%s -> { %a }@." s (Utils.fprintf_list ~sep:", " Format.pp_print_string) (ISet.elements t)) death;
141
    Format.fprintf fmt "}@."
142
  end
143

    
144

    
145
(* Reuse policy:
146
   - could reuse variables with the same type exactly only (simple).
147
   - reusing variables with different types would involve:
148
     - either dirty castings
149
     - or complex inclusion expression (for instance: array <-> array cell, struct <-> struct field) to be able to reuse only some parts of structured data.
150
     ... it seems too complex and potentially unsafe
151
   - for node instance calls: output variables could NOT reuse input variables, 
152
     even if inputs become dead, because the correctness would depend on the scheduling
153
     of the callee (so, the compiling strategy could NOT be modular anymore).
154
   - once a policy is set, we need to:
155
     - replace each variable by its reuse alias.
156
     - simplify resulting equations, as we may now have:
157
        x = x;                     --> ;           for scalar vars
158
       or:
159
        x = &{ f1 = x->f1; f2 = t; } --> x->f2 = t;   for struct vars
160
     - such simplifications are, until now, only expressible at the C source level...
161
 *)
162

    
163
(* Replaces [v] by [v'] in set [s] *)
164
let replace_in_set s v v' =
165
  if ISet.mem v s then ISet.add v' (ISet.remove v s) else s
166

    
167
(* Replaces [v] by [v'] in death table [death] *)
168
let replace_in_death_table death v v' =
169
 Hashtbl.iter (fun k dead -> Hashtbl.replace death k (replace_in_set dead v v')) death
170

    
171
let find_compatible_local node var dead =
172
 (*Format.eprintf "find_compatible_local %s %s@." node.node_id var;*)
173
  let typ = (Corelang.node_var var node).var_type in
174
  let eq_var = node_eq var node in
175
  let inputs =
176
    match NodeDep.get_callee eq_var.eq_rhs with
177
    | None           -> []
178
    | Some (_, args) -> List.fold_right (fun e r -> match e.expr_desc with Expr_ident id -> id::r | _ -> r) args [] in
179
  let filter v =
180
       ISet.mem v.var_id dead
181
    && Typing.eq_ground typ v.var_type
182
    && not (List.mem v.var_id inputs) in
183
  try
184
    Some ((List.find filter node.node_locals).var_id)
185
  with Not_found -> None
186

    
187
let reuse_policy node sort death =
188
  let dead = ref ISet.empty in
189
  let policy = Hashtbl.create 23 in
190
  let sort = ref sort in
191
  while !sort <> []
192
  do
193
    let head = List.hd !sort in
194
    if Hashtbl.mem death head then
195
      begin
196
	dead := ISet.union (Hashtbl.find death head) !dead;
197
      end;
198
    (match find_compatible_local node head !dead with
199
    | None   -> ()
200
    | Some l -> replace_in_death_table death head l; Hashtbl.add policy head l);
201
    sort := List.tl !sort;
202
  done;
203
  policy
204
 
205
let pp_reuse_policy fmt policy =
206
  begin
207
    Format.fprintf fmt "{ /* reuse policy */@.";
208
    Hashtbl.iter (fun s t -> Format.fprintf fmt "%s -> %s@." s t) policy;
209
    Format.fprintf fmt "}@."
210
  end
211
(* Local Variables: *)
212
(* compile-command:"make -C .." *)
213
(* End: *)
(27-27/49)