Skip to content
Snippets Groups Projects
l2lSplit.ml 13.5 KiB
Newer Older
(** After this lic2lic pass, there is only one operator per equation.
Pascal Raymond's avatar
Pascal Raymond committed

Source 2 source transformation :
Pascal Raymond's avatar
Pascal Raymond committed

CONDITION :
- après L2lRmPoly (et DoAliasType ?)
Pascal Raymond's avatar
Pascal Raymond committed
*)
Pascal Raymond's avatar
Pascal Raymond committed

let dbg=Some (Verbose.get_flag "split")
(********************************************************************************)
Pascal Raymond's avatar
Pascal Raymond committed
let new_var getid type_eff clock_eff = 
  let id = getid "v" in
      var_nature_eff = AstCore.VarLocal;
      var_number_eff = -1; (* this field is used only for i/o. 
                              Should i rather put something sensible there ? *)
      var_type_eff   = type_eff;
      var_clock_eff  = id,clock_eff;
Pascal Raymond's avatar
Pascal Raymond committed
    } in
(********************************************************************************)
(* functions that deal with tuple breaking *)
let rec (get_vel_from_tuple : val_exp -> val_exp list) =
    | { ve_core = CallByPosLic({it=Lic.TUPLE }, OperLic vel) } -> 
        List.flatten (List.map get_vel_from_tuple vel)
    | ve -> [ve]

let to_be_broken = function
    (* We are only interested in operators that can deal with tuples! *)
  | CallByPosLic({ it = Lic.ARROW }, _) -> true
  | CallByPosLic({ it = Lic.FBY }, _) -> true
  | CallByPosLic({ it = Lic.PRE }, _) -> true
  | CallByPosLic({ it = Lic.CURRENT }, _) -> true
  | CallByPosLic({ it = Lic.TUPLE }, _) -> true
  | CallByPosLic({ it = Lic.WHEN _ }, _) -> true
  | CallByPosLic({ it = Lic.PREDEF_CALL(AstPredef.IF_n, []) }, _) -> true
  | _ -> false


let (break_it : val_exp -> val_exp list) =
      match ve.ve_core with
	| CallByPosLic({it=Lic.PREDEF_CALL(AstPredef.IF_n,[]);src=lxm}, OperLic [c;ve1;ve2]) ->
            let vel1 = get_vel_from_tuple ve1
            and vel2 = get_vel_from_tuple ve2 
            in
              List.map2
		(fun ve1 ve2 -> 
                       CallByPosLic({it=Lic.PREDEF_CALL(AstPredef.IF_n,[]);src=lxm}, 
                                    OperLic [c;ve1;ve2]);
                     ve_typ = ve1.ve_typ;
                     ve_clk = ve1.ve_clk;
Erwan Jahier's avatar
Erwan Jahier committed

	| CallByPosLic({it=WHEN clk; src=lxm}, OperLic vel) ->
            let vel = List.flatten (List.map get_vel_from_tuple vel) in
              List.map 
                       ve_core=CallByPosLic({it=WHEN clk ; src=lxm }, OperLic [ve])}) 
	| CallByPosLic({it=Lic.TUPLE ; src=lxm }, OperLic vel) ->
            let vel = List.flatten (List.map get_vel_from_tuple vel) in
              List.map 
                       ve_core=CallByPosLic({it=Lic.TUPLE ; src=lxm }, OperLic [ve])}) 
	| CallByPosLic({it=op ; src=lxm }, OperLic [ve]) ->
                (fun ve -> { ve with ve_core=CallByPosLic({it=op;src=lxm}, OperLic [ve])})
	| CallByPosLic({it=op ; src=lxm }, OperLic [ve1;ve2]) ->
            let vel1 = get_vel_from_tuple ve1
            and vel2 = get_vel_from_tuple ve2 
            in
              List.map2
		(fun ve1 ve2 -> 
		   { ve_core = CallByPosLic({it=op ; src=lxm }, OperLic [ve1;ve2]);
                     ve_typ = ve1.ve_typ;
                     ve_clk = ve1.ve_clk }
	| _ -> assert false (* dead code since it is guarded by to_be_broken... *)
    let tl = ve.ve_typ
    and cl = ve.ve_clk in
    let nvel = List.map2 (fun nve t -> { nve with ve_typ = [t]; ve_clk=cl } ) nvel ve.ve_typ in
      assert(ve.ve_typ = tl);
let (split_tuples:Lic.eq_info Lxm.srcflagged list -> Lic.eq_info Lxm.srcflagged list) =
  fun eql -> 
    let split_one_eq eq = 
      let { src = lxm_eq ; it = (lhs, n_rhs) } = eq in
        if List.length lhs > 1 && (to_be_broken n_rhs.ve_core) then
          let vel = break_it n_rhs in
          let eqs = 
            try List.map2 (fun lhs ve -> [lhs], ve) lhs vel 
            with _ -> 
              assert false
          in
          let eqs = List.map (fun eq -> Lxm.flagit eq lxm_eq) eqs in
            eqs
        else
          [eq]

    in
      List.flatten (List.map split_one_eq eql)
(********************************************************************************)
(* The functions below accumulate 
   (1) the new equations 
   (2) the fresh variables. 
*)
type split_acc = (Lic.eq_info srcflagged) list * Lic.var_info list
let rec (eq : LicPrg.id_generator -> Lic.eq_info Lxm.srcflagged -> split_acc) =
Pascal Raymond's avatar
Pascal Raymond committed
  fun getid { src = lxm_eq ; it = (lhs, rhs) } ->
    let n_rhs, (neqs, nlocs) = split_val_exp false true getid rhs in
      { src = lxm_eq ; it = (lhs, n_rhs) }::neqs, nlocs
       LicPrg.id_generator -> split_acc -> Lic.eq_info srcflagged -> split_acc) =
Pascal Raymond's avatar
Pascal Raymond committed
  fun getid (eqs, locs) equation -> 
    let (neqs, nlocs) = eq getid equation in 
      (split_tuples (eqs@neqs), locs@nlocs)
        
and (split_val_exp : bool -> bool -> LicPrg.id_generator -> Lic.val_exp -> 
      Lic.val_exp * split_acc) =
Pascal Raymond's avatar
Pascal Raymond committed
  fun when_flag top_level getid ve -> 
    (* [when_flag] is true is the call is made from a "when" statement.
       We need this flag in order to know if it is necessary to add
       a when on constants. Indeed, in Lustre V6, it is not necessary
       to write " 1 when clk + x " if x in on clk (it's more sweet). 
       So we need to add it  (because if we split "1+1+x", then it
       is hard to know the "1" are on the clock of x ; moreover, lustre
       v4 (and the other backends) cannot infer such clock).

       But is is not forbidden either! so we need to make sure that there
       is no "when"...
    *)
    match ve.ve_core with
      | CallByPosLic({it=Lic.VAR_REF _}, _) -> ve, ([],[])
      | CallByPosLic({it=Lic.CONST_REF _}, _) -> ve, ([],[])
      | CallByPosLic({src=lxm;it=Lic.PREDEF_CALL(AstPredef.TRUE_n,_)}, _) 
      | CallByPosLic({src=lxm;it=Lic.PREDEF_CALL(AstPredef.FALSE_n,_)}, _) 
      | CallByPosLic({src=lxm;it=Lic.PREDEF_CALL(AstPredef.ICONST_n _,_)}, _) 
      | CallByPosLic({src=lxm;it=Lic.PREDEF_CALL(AstPredef.RCONST_n _,_)}, _) 
          (* We do not create an intermediary variable for those, 
             but 
          *)
        -> if not when_flag then
          let clk = ve.ve_clk in
                  let clk_exp = AstCore.NamedClock (Lxm.flagit clock lxm) in
                    { ve with ve_core = 
                        CallByPosLic({src=lxm;it=Lic.WHEN clk_exp},OperLic [ve])},
              | (ClockVar _) (* should not occur *)
              | BaseLic  -> ve, ([],[])
      | CallByNameLic (by_name_op_eff, fl) ->
          let lxm = by_name_op_eff.src in 
Erwan Jahier's avatar
Erwan Jahier committed
          let fl, eql, vl = 
            List.fold_left
              (fun (fl_acc, eql_acc, vl_acc) (fn, fv) ->
Pascal Raymond's avatar
Pascal Raymond committed
                 let fv, (eql, vl) = split_val_exp false false getid fv in
Erwan Jahier's avatar
Erwan Jahier committed
                   ((fn,fv)::fl_acc, eql@eql_acc, vl@vl_acc)
              )
              ([],[],[])
Erwan Jahier's avatar
Erwan Jahier committed
          in
          let rhs = { ve with ve_core = CallByNameLic (by_name_op_eff, List.rev fl) } in
            else
              (* create the var for the current call *)
              let clk_l = ve.ve_clk in 
              let typ_l = ve.ve_typ in  
Pascal Raymond's avatar
Pascal Raymond committed
              let nv_l = List.map2 (new_var getid) typ_l clk_l  in
              let nve = match nv_l with
                | [nv] -> { ve with ve_core = 
                      CallByPosLic(
                        Lxm.flagit (Lic.VAR_REF (nv.var_name_eff)) lxm,
                        OperLic [] 
              let lpl = List.map (fun nv -> LeftVarLic(nv, lxm)) nv_l in
              let eq = Lxm.flagit (lpl, rhs) lxm in
      | CallByPosLic(by_pos_op_eff, OperLic vel) -> (
          (* recursively split the arguments *) 
          let lxm = by_pos_op_eff.src in
                (* for WITH and HAT, a particular treatment is done because
                   the val_exp is attached to them *)
              | Lic.WITH(ve) ->
Pascal Raymond's avatar
Pascal Raymond committed
                  let ve, (eql, vl) = split_val_exp false false getid ve in
                  let by_pos_op_eff = Lxm.flagit (Lic.WITH(ve)) lxm in
                  let rhs = CallByPosLic(by_pos_op_eff, OperLic []) in
              | Lic.HAT(i,ve) ->
Pascal Raymond's avatar
Pascal Raymond committed
                  let ve, (eql, vl) = split_val_exp false false getid ve in
                  let by_pos_op_eff = Lxm.flagit (Lic.HAT(i, ve)) lxm in
                  let rhs = CallByPosLic(by_pos_op_eff, OperLic []) in
              | Lic.WHEN ve -> (* should we create a var for the clock? *)
Pascal Raymond's avatar
Pascal Raymond committed
                  let vel,(eql, vl) = split_val_exp_list true false getid vel in
                  let by_pos_op_eff = Lxm.flagit (Lic.WHEN(ve)) lxm in
                  let rhs = CallByPosLic(by_pos_op_eff, OperLic vel) in
              | Lic.ARRAY vel ->
Pascal Raymond's avatar
Pascal Raymond committed
                  let vel, (eql, vl) = split_val_exp_list false false getid vel in
                  let by_pos_op_eff = Lxm.flagit (Lic.ARRAY(vel)) lxm in
                  let rhs = CallByPosLic(by_pos_op_eff, OperLic []) in
                    rhs, (eql, vl)
Pascal Raymond's avatar
Pascal Raymond committed
                  let vel, (eql, vl) = split_val_exp_list false false getid vel in
                  let rhs = CallByPosLic(by_pos_op_eff, OperLic vel) in
          let rhs = { ve with ve_core = rhs } in
	    if top_level || by_pos_op_eff.it = TUPLE then 
            else
              (* create the var for the current call *)
              let clk_l = ve.ve_clk in 
              let typ_l = ve.ve_typ in
Pascal Raymond's avatar
Pascal Raymond committed
              let nv_l = List.map2 (new_var getid) typ_l clk_l  in
              let nve = 
                match nv_l with
                  | [nv] -> {
                      ve_typ = [nv.var_type_eff];
                      ve_clk = clk_l; 
                      ve_core = CallByPosLic(
                        Lxm.flagit (Lic.VAR_REF (nv.var_name_eff)) lxm,
                        OperLic [])		
                      ve_typ = List.map (fun v -> v.var_type_eff) nv_l;
                      ve_clk = clk_l;
		      ve_core = CallByPosLic(
                        Lxm.flagit Lic.TUPLE lxm, 
                        OperLic
                                 ve_core = CallByPosLic 
                                      (Lic.VAR_REF (nv.var_name_eff)) lxm,
				    OperLic []);
                                 ve_typ = [nv.var_type_eff];
                                 ve_clk = [snd nv.var_clock_eff]
	      let lpl = List.map (fun nv -> LeftVarLic(nv, lxm)) nv_l in
              let eq = Lxm.flagit (lpl, rhs) lxm in
and (split_val_exp_list : bool -> 
      bool -> LicPrg.id_generator -> Lic.val_exp list -> Lic.val_exp list * split_acc) =
Pascal Raymond's avatar
Pascal Raymond committed
  fun when_flag top_level getid vel ->
Pascal Raymond's avatar
Pascal Raymond committed
      List.split (List.map (split_val_exp when_flag top_level getid) vel) 
    let eqll,vll = List.split accl in
    let eql, vl = List.flatten eqll, List.flatten vll in
      (vel,(eql,vl))

and split_node (getid: LicPrg.id_generator) (n: Lic.node_exp) : Lic.node_exp =
Pascal Raymond's avatar
Pascal Raymond committed
   Verbose.printf ~flag:dbg "*** Splitting node  %s\n"
      (LicDump.string_of_node_key_iter n.node_key_eff);
   let res = match n.def_eff with
   | ExternLic 
   | MetaOpLic _
   | AbstractLic None -> n
   | AbstractLic (Some pn) -> 
      { n with def_eff = AbstractLic (Some (split_node getid pn)) }
   | BodyLic b -> 
Pascal Raymond's avatar
Pascal Raymond committed
      let loc = match n.loclist_eff with None -> [] | Some l -> l in
      let (neqs, nv) = List.fold_left (split_eq_acc getid) ([], loc) b.eqs_eff in
      let asserts = List.map (fun x -> x.it) b.asserts_eff in
      let lxm_asserts = List.map (fun x -> x.src) b.asserts_eff in
      let nasserts,(neqs_asserts,nv_asserts) =
         split_val_exp_list false true getid asserts
      in
      let nasserts = List.map2 Lxm.flagit nasserts lxm_asserts in
      let (neqs, nv) =  (neqs@neqs_asserts, nv@nv_asserts) in
      let nb = { eqs_eff = neqs ; asserts_eff = nasserts } in
              { n with loclist_eff = Some nv; def_eff = BodyLic nb }
Pascal Raymond's avatar
Pascal Raymond committed
   in
   res

let rec doit (inprg : LicPrg.t) : LicPrg.t =
   (* n.b. on fait un minumum d'effet de bord pour
      pas avoir trop d'acummulateur ... *)
   let res = ref LicPrg.empty in

   (** TRAITE LES TYPES *)
   let do_type k (te:Lic.type_) =
Pascal Raymond's avatar
Pascal Raymond committed
      res := LicPrg.add_type k te !res
   in
   LicPrg.iter_types do_type inprg;

   (** TRAITE LES CONSTANTES *)
   let do_const k (ec: Lic.const) =
Pascal Raymond's avatar
Pascal Raymond committed
      res := LicPrg.add_const k ec !res
   in 
   LicPrg.iter_consts do_const inprg ;

   (** TRAITE LES NOEUDS : *)
   let rec do_node k (ne:Lic.node_exp) =
Pascal Raymond's avatar
Pascal Raymond committed
      (* On passe en parametre un constructeur de nouvelle variable locale *)
      let getid = LicPrg.fresh_var_id_generator inprg ne in
      let ne' = split_node getid ne in
      res := LicPrg.add_node k ne' !res
   in
   (*LET's GO *)
   LicPrg.iter_nodes do_node inprg;
   !res