Project

General

Profile

Download (11.7 KB) Statistics
| Branch: | Tag: | Revision:
1

    
2
open Machine_code_types
3
open Lustre_types
4
open Corelang
5
(*
6
open Machine_code_common
7
*)
8

    
9
let is_machine_statefull m = not m.mname.node_dec_stateless
10

    
11
(** Return true if its the arrow machine
12
   @param machine the machine to test
13
*)
14
let is_arrow machine = String.equal Arrow.arrow_id machine.mname.node_id
15

    
16
(** Extract a node from an instance.
17
   @param instance the instance
18
**)
19
let extract_node instance =
20
  let (_, (node, _)) = instance in
21
  match node.top_decl_desc with
22
    | Node nd         -> nd
23
    | _ -> assert false (*TODO*)
24

    
25
(** Extract from a machine list the one corresponding to the given instance.
26
      assume that the machine is in the list.
27
   @param machines list of all machines
28
   @param instance instance of a machine
29
   @return the machine corresponding to hte given instance
30
**)
31
let get_machine machines instance =
32
    let id = (extract_node instance).node_id in
33
    try
34
      List.find (function m -> m.mname.node_id=id) machines
35
    with
36
      Not_found -> assert false (*TODO*)
37

    
38
(** Extract all the inputs and outputs.
39
   @param machine the machine
40
   @return a list of all the var_decl of a macine
41
**)
42
let get_all_vars_machine m =
43
  m.mmemory@m.mstep.step_inputs@m.mstep.step_outputs@m.mstatic
44

    
45
(** Check if a type is polymorphic.
46
   @param typ the type
47
   @return true if its polymorphic
48
**)
49
let is_Tunivar typ = (Types.repr typ).tdesc == Types.Tunivar
50

    
51
(** Find all polymorphic type : Types.Tunivar in a machine.
52
   @param machine the machine
53
   @return a list of id corresponding to polymorphic type
54
**)
55
let find_all_polymorphic_type m =
56
  let vars = get_all_vars_machine m in
57
  let extract id = id.var_type.tid in
58
  let polymorphic_type_vars =
59
    List.filter (function x-> is_Tunivar x.var_type) vars in
60
  List.sort_uniq (-) (List.map extract polymorphic_type_vars)
61

    
62

    
63
(** Check if a submachine is statefull.
64
    @param submachine a submachine
65
    @return true if the submachine is statefull
66
**)
67
let is_submachine_statefull submachine =
68
    not (snd (snd submachine)).mname.node_dec_stateless
69

    
70
(** Find a submachine step call in a list of instructions.
71
    @param ident submachine instance ident
72
    @param instr_list List of instruction sto search
73
    @return a list of pair containing input types and output types for each step call found
74
**)
75
let rec find_submachine_step_call ident instr_list =
76
  let search_instr instruction = 
77
    match instruction.instr_desc with
78
      | MStep (il, i, vl) when String.equal i ident -> [
79
        (List.map (function x-> x.value_type) vl,
80
            List.map (function x-> x.var_type) il)]
81
      | MBranch (_, l) -> List.flatten
82
          (List.map (function x, y -> find_submachine_step_call ident y) l)
83
      | _ -> []
84
  in
85
  List.flatten (List.map search_instr instr_list)
86

    
87
(* Replace this function by check_type_equal but be careful to the fact that
88
   this function chck equality and that it is both basic type.
89
   This might be a required feature when it used *)
90
(** Test if two types are the same.
91
   @param typ1 the first type
92
   @param typ2 the second type
93
**)
94
let pp_eq_type typ1 typ2 = 
95
  let get_basic typ = match (Types.repr typ).Types.tdesc with
96
    | Types.Tbasic Types.Basic.Tint -> Types.Basic.Tint
97
    | Types.Tbasic Types.Basic.Treal -> Types.Basic.Treal
98
    | Types.Tbasic Types.Basic.Tbool -> Types.Basic.Tbool
99
    | _ -> assert false (*TODO*)
100
  in
101
  get_basic typ1 = get_basic typ2
102

    
103
(** Check that two types are the same.
104
   @param t1 a type
105
   @param t2 an other type
106
   @param return true if the two types are Tbasic or Tunivar and equal
107
**)
108
let rec check_type_equal (t1:Types.type_expr) (t2:Types.type_expr) =
109
  match (Types.repr t1).Types.tdesc, (Types.repr t2).Types.tdesc with
110
    | Types.Tbasic x, Types.Tbasic y -> x = y
111
    | Types.Tunivar,  Types.Tunivar  -> t1.tid = t2.tid
112
    | Types.Ttuple l, _ -> assert (List.length l = 1); check_type_equal (List.hd l) t2
113
    | _, Types.Ttuple l -> assert (List.length l = 1); check_type_equal t1 (List.hd l)
114
    | Types.Tstatic (_, t), _ -> check_type_equal t t2
115
    | _, Types.Tstatic (_, t) -> check_type_equal t1 t
116
    | _ -> assert false
117

    
118
(** Extend a substitution to unify the two given types. Only the
119
  first type can be polymorphic.
120
    @param subsitution the base substitution
121
    @param type_poly the type which can be polymorphic
122
    @param typ the type to match type_poly with
123
**)
124
let unification (substituion:(int*Types.type_expr) list) ((type_poly:Types.type_expr), (typ:Types.type_expr)) =
125
  assert(not (is_Tunivar typ));
126
  (* If type_poly is polymorphic *)
127
  if is_Tunivar type_poly then
128
    (* If a subsitution exists for it *)
129
    if List.mem_assoc type_poly.tid substituion then
130
    begin
131
      (* We check that the type corresponding to type_poly in the subsitution
132
         match typ *)
133
      (try
134
        assert(check_type_equal (List.assoc type_poly.tid substituion) typ)
135
      with
136
        Not_found -> assert false);
137
      (* We return the original substituion, it is already correct *)
138
      substituion
139
    end
140
    (* If type_poly is not in the subsitution *)
141
    else
142
      (* We add it to the substituion *)
143
      (type_poly.tid, typ)::substituion
144
  (* iftype_poly is not polymorphic *)
145
  else
146
  begin
147
    (* We check that type_poly and typ are the same *)
148
    assert(check_type_equal type_poly typ);
149
    (* We return the original substituion, it is already correct *)
150
    substituion
151
  end
152

    
153
(** Check that two calls are equal. A call is
154
  a pair of list of types, the inputs and the outputs.
155
   @param calls a list of pair of list of types
156
   @param return true if the two pairs are equal
157
**)
158
let check_call_equal (i1, o1) (i2, o2) =
159
  (List.for_all2 check_type_equal i1 i2)
160
    && (List.for_all2 check_type_equal i1 i2)
161

    
162
(** Check that all the elements of list of calls are equal to one.
163
  A call is a pair of list of types, the inputs and the outputs.
164
   @param call a pair of list of types
165
   @param calls a list of pair of list of types
166
   @param return true if all the elements are equal
167
**)
168
let check_calls call calls =
169
  List.for_all (check_call_equal call) calls
170

    
171
(** Extract from a subinstance that can have polymorphic type the instantiation
172
    of all its polymorphic type instanciation for a given machine. It searches
173
    the step calls and extract a substitution for all polymorphic type from
174
    it.
175
   @param machine the machine which instantiate the subinstance
176
   @param ident the identifier of the instance which permits to find the step call
177
   @param submachine the machine corresponding to the subinstance
178
   @return the correspondance between polymorphic type id and their instantiation
179
**)
180
let get_substitution machine ident submachine =
181
  (* extract the calls to submachines from the machine *)
182
  let calls = find_submachine_step_call ident machine.mstep.step_instrs in
183
  (* extract the first call  *)
184
  let call = match calls with
185
              (* assume that there is always one call to a subinstance *)
186
              | []    -> assert(false)
187
              | h::t  -> h in
188
  (* assume that all the calls to a subinstance are using the same type *)
189
  assert(check_calls call calls);
190
  (* make a list of all types from input and output vars *)
191
  let call_types = (fst call)@(snd call) in
192
  (* extract all the input and output vars from the submachine *)
193
  let machine_vars = submachine.mstep.step_inputs@submachine.mstep.step_outputs in
194
  (* keep only the type of vars *)
195
  let machine_types = List.map (function x-> x.var_type) machine_vars in
196
  (* assume that there is the same numer of input and output in the submachine
197
      and the call *)
198
  assert (List.length machine_types = List.length call_types);
199
  (* Unify the two lists of types *)
200
  let substitution = List.fold_left unification [] (List.combine machine_types call_types) in
201
  (* Assume that our substitution match all the possible
202
       polymorphic type of the node *)
203
  let polymorphic_types = find_all_polymorphic_type submachine in
204
  assert (List.length polymorphic_types = List.length substitution);
205
  (try
206
    assert (List.for_all (fun x -> List.mem_assoc x substitution) polymorphic_types)
207
  with
208
    Not_found -> assert false);
209
  substitution
210

    
211

    
212
(** Extract from a machine the instance corresponding to the identifier,
213
      assume that the identifier exists in the instances of the machine.
214

    
215
   @param identifier the instance identifier
216
   @param machine a machine
217
   @return the instance of machine.minstances corresponding to identifier
218
**)
219
let get_instance identifier typed_submachines =
220
  try
221
    List.assoc identifier typed_submachines
222
  with Not_found -> assert false
223

    
224
(*Usefull for debug*)
225
let pp_type_debug fmt typ = 
226
  (match (Types.repr typ).Types.tdesc with
227
    | Types.Tbasic Types.Basic.Tint  -> Format.fprintf fmt "INTEGER"
228
    | Types.Tbasic Types.Basic.Treal -> Format.fprintf fmt "FLOAT"
229
    | Types.Tbasic Types.Basic.Tbool -> Format.fprintf fmt "BOOLEAN"
230
    | Types.Tunivar                  -> Format.fprintf fmt "POLY(%i)" typ.Types.tid
231
    | _ -> assert false
232
  )
233

    
234
let build_if g c1 i1 tl =
235
  let neg = c1=tag_false in
236
  let other = match tl with
237
    | []         -> None
238
    | [(c2, i2)] -> Some i2
239
    | _          -> assert false
240
  in
241
  match neg, other with
242
    | true, Some x -> (false, g, x, Some i1)
243
    | _ ->
244
  (neg, g, i1, other)
245

    
246
let rec push_if_in_expr = function
247
  | [] -> []
248
  | instr::q ->
249
    (
250
      match get_instr_desc instr with
251
        | MBranch (g, (c1, i1)::tl) when c1=tag_false || c1=tag_true ->
252
            let (neg, g, instrs1, instrs2) = build_if g c1 i1 tl in
253
            let instrs1_pushed = push_if_in_expr instrs1 in
254
            let get_assign instr = match get_instr_desc instr with
255
              | MLocalAssign (id, value) -> (false, id, value)
256
              | MStateAssign (id, value) -> (true, id, value)
257
              | _ -> assert false
258
            in
259
            let gen_eq ident state value1 value2 =
260
              assert(check_type_equal ident.var_type value1.value_type);
261
              assert(check_type_equal ident.var_type value2.value_type);
262
              let value = {
263
                            value_desc   = Fun ("ite", [g;value1;value2]);
264
                            value_type   = ident.var_type;
265
                            value_annot  = None
266
                          }
267
              in
268
              let assign = if state then MStateAssign (ident, value) else MLocalAssign (ident, value) in
269
              { instr_desc = assign;
270
                lustre_eq  = None
271
              }
272
            in
273
            let mkval_var id = {
274
                              value_desc   = Var id;
275
                              value_type   = id.var_type;
276
                              value_annot  = None
277
                            }
278
            in
279
            let rec find_split s1 id1 accu = function
280
              | [] -> [], accu, mkval_var id1
281
              | (s2, id2, v2)::q when s1 = s2
282
                                  && id1.var_id = id2.var_id -> accu, q, v2
283
              | t::q -> find_split s1 id1 (t::accu) q
284
            in
285
            let gen_from_else l =
286
              List.map
287
                (fun (s2, id2, v2) -> gen_eq id2 s2 (mkval_var id2) v2)
288
                l
289
            in
290
            let rec gen_assigns if_assigns else_assigns =
291
              let res, accu_else = match if_assigns with
292
                | (s1, id1, v1)::q ->
293
                  let accu, remain, v2 = find_split s1 id1 [] else_assigns in
294
                  (gen_eq id1 s1 v1 v2)::(gen_assigns q remain), accu
295
                | [] -> [], else_assigns
296
              in
297
              (gen_from_else accu_else)@res
298
            in
299
            let if_assigns = List.map get_assign instrs1_pushed in
300
            let else_assigns = match instrs2 with
301
              | None -> []
302
              | Some instrs2 -> 
303
                  let instrs2_pushed = push_if_in_expr instrs2 in
304
                  List.map get_assign instrs2_pushed
305
            in
306
            gen_assigns if_assigns else_assigns
307
        | x -> [instr]
308
      )@(push_if_in_expr q)
309

    
310

    
311

    
312

    
(11-11/12)