Project

General

Profile

Download (11.3 KB) Statistics
| Branch: | Tag: | Revision:
1
open Machine_code_types
2
open Lustre_types
3
open Corelang
4
(* open Machine_code_common *)
5

    
6
let is_machine_statefull m = not m.mname.node_dec_stateless
7

    
8
(** Return true if its the arrow machine @param machine the machine to test *)
9
let is_arrow machine = String.equal Arrow.arrow_id machine.mname.node_id
10

    
11
(** Extract a node from an instance. @param instance the instance **)
12
let extract_node instance =
13
  let _, (node, _) = instance in
14
  match node.top_decl_desc with Node nd -> nd | _ -> assert false
15
(*TODO*)
16

    
17
(** Extract from a machine list the one corresponding to the given instance.
18
    assume that the machine is in the list. @param machines list of all machines
19
    @param instance instance of a machine @return the machine corresponding to
20
    hte given instance **)
21
let get_machine machines instance =
22
  let id = (extract_node instance).node_id in
23
  try List.find (function m -> m.mname.node_id = id) machines
24
  with Not_found -> assert false
25
(*TODO*)
26

    
27
(** Extract all the inputs and outputs. @param machine the machine @return a
28
    list of all the var_decl of a macine **)
29
let get_all_vars_machine m =
30
  m.mmemory @ m.mstep.step_inputs @ m.mstep.step_outputs @ m.mstatic
31

    
32
(** Check if a type is polymorphic. @param typ the type @return true if its
33
    polymorphic **)
34
let is_Tunivar typ = (Types.repr typ).tdesc == Types.Tunivar
35

    
36
(** Find all polymorphic type : Types.Tunivar in a machine. @param machine the
37
    machine @return a list of id corresponding to polymorphic type **)
38
let find_all_polymorphic_type m =
39
  let vars = get_all_vars_machine m in
40
  let extract id = id.var_type.tid in
41
  let polymorphic_type_vars =
42
    List.filter (function x -> is_Tunivar x.var_type) vars
43
  in
44
  List.sort_uniq ( - ) (List.map extract polymorphic_type_vars)
45

    
46
(** Check if a submachine is statefull. @param submachine a submachine @return
47
    true if the submachine is statefull **)
48
let is_submachine_statefull submachine =
49
  not (snd (snd submachine)).mname.node_dec_stateless
50

    
51
(** Find a submachine step call in a list of instructions. @param ident
52
    submachine instance ident @param instr_list List of instruction sto search
53
    @return a list of pair containing input types and output types for each step
54
    call found **)
55
let rec find_submachine_step_call ident instr_list =
56
  let search_instr instruction =
57
    match instruction.instr_desc with
58
    | MStep (il, i, vl) when String.equal i ident ->
59
      [
60
        ( List.map (function x -> x.value_type) vl,
61
          List.map (function x -> x.var_type) il );
62
      ]
63
    | MBranch (_, l) ->
64
      List.flatten
65
        (List.map (function _, y -> find_submachine_step_call ident y) l)
66
    | _ ->
67
      []
68
  in
69
  List.flatten (List.map search_instr instr_list)
70

    
71
(* Replace this function by check_type_equal but be careful to the fact that
72
   this function chck equality and that it is both basic type. This might be a
73
   required feature when it used *)
74

    
75
(** Test if two types are the same. @param typ1 the first type @param typ2 the
76
    second type **)
77
let pp_eq_type typ1 typ2 =
78
  let get_basic typ =
79
    match (Types.repr typ).Types.tdesc with
80
    | Types.Tbasic Types.Basic.Tint ->
81
      Types.Basic.Tint
82
    | Types.Tbasic Types.Basic.Treal ->
83
      Types.Basic.Treal
84
    | Types.Tbasic Types.Basic.Tbool ->
85
      Types.Basic.Tbool
86
    | _ ->
87
      assert false
88
    (*TODO*)
89
  in
90
  get_basic typ1 = get_basic typ2
91

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

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

    
139
(** Check that two calls are equal. A call is a pair of list of types, the
140
    inputs and the outputs. @param calls a list of pair of list of types @param
141
    return true if the two pairs are equal **)
142
let check_call_equal (i1, _) (i2, _) =
143
  List.for_all2 check_type_equal i1 i2 && List.for_all2 check_type_equal i1 i2
144

    
145
(** Check that all the elements of list of calls are equal to one. A call is a
146
    pair of list of types, the inputs and the outputs. @param call a pair of
147
    list of types @param calls a list of pair of list of types @param return
148
    true if all the elements are equal **)
149
let check_calls call calls = List.for_all (check_call_equal call) calls
150

    
151
(** Extract from a subinstance that can have polymorphic type the instantiation
152
    of all its polymorphic type instanciation for a given machine. It searches
153
    the step calls and extract a substitution for all polymorphic type from it.
154
    @param machine the machine which instantiate the subinstance @param ident
155
    the identifier of the instance which permits to find the step call @param
156
    submachine the machine corresponding to the subinstance @return the
157
    correspondance between polymorphic type id and their instantiation **)
158
let get_substitution machine ident submachine =
159
  (* extract the calls to submachines from the machine *)
160
  let calls = find_submachine_step_call ident machine.mstep.step_instrs in
161
  (* extract the first call *)
162
  let call =
163
    match calls with
164
    (* assume that there is always one call to a subinstance *)
165
    | [] ->
166
      assert false
167
    | h :: _ ->
168
      h
169
  in
170
  (* assume that all the calls to a subinstance are using the same type *)
171
  assert (check_calls call calls);
172
  (* make a list of all types from input and output vars *)
173
  let call_types = fst call @ snd call in
174
  (* extract all the input and output vars from the submachine *)
175
  let machine_vars =
176
    submachine.mstep.step_inputs @ submachine.mstep.step_outputs
177
  in
178
  (* keep only the type of vars *)
179
  let machine_types = List.map (function x -> x.var_type) machine_vars in
180
  (* assume that there is the same numer of input and output in the submachine
181
     and the call *)
182
  assert (List.length machine_types = List.length call_types);
183
  (* Unify the two lists of types *)
184
  let substitution =
185
    List.fold_left unification [] (List.combine machine_types call_types)
186
  in
187
  (* Assume that our substitution match all the possible polymorphic type of the
188
     node *)
189
  let polymorphic_types = find_all_polymorphic_type submachine in
190
  assert (List.length polymorphic_types = List.length substitution);
191
  (try
192
     assert (
193
       List.for_all (fun x -> List.mem_assoc x substitution) polymorphic_types)
194
   with Not_found -> assert false);
195
  substitution
196

    
197
(** Extract from a machine the instance corresponding to the identifier, assume
198
    that the identifier exists in the instances of the machine.
199

    
200
    @param identifier the instance identifier @param machine a machine @return
201
    the instance of machine.minstances corresponding to identifier **)
202
let get_instance identifier typed_submachines =
203
  try List.assoc identifier typed_submachines with Not_found -> assert false
204

    
205
(*Usefull for debug*)
206
let pp_type_debug fmt typ =
207
  match (Types.repr typ).Types.tdesc with
208
  | Types.Tbasic Types.Basic.Tint ->
209
    Format.fprintf fmt "INTEGER"
210
  | Types.Tbasic Types.Basic.Treal ->
211
    Format.fprintf fmt "FLOAT"
212
  | Types.Tbasic Types.Basic.Tbool ->
213
    Format.fprintf fmt "BOOLEAN"
214
  | Types.Tunivar ->
215
    Format.fprintf fmt "POLY(%i)" typ.Types.tid
216
  | _ ->
217
    assert false
218

    
219
let build_if g c1 i1 tl =
220
  let neg = c1 = tag_false in
221
  let other =
222
    match tl with [] -> None | [ (_, i2) ] -> Some i2 | _ -> assert false
223
  in
224
  match neg, other with
225
  | true, Some x ->
226
    false, g, x, Some i1
227
  | _ ->
228
    neg, g, i1, other
229

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