Newer
Older
(** Time-stamp: <modified the 13/05/2009 (at 16:35) by Erwan Jahier> *)
open Lxm
open Eff
(********************************************************************************)
(* stuff to create fresh var names. *)
let new_var str node_env type_eff clock_eff =
let id = Ident.of_string (Name.new_local_var str) in
let var =
{
var_name_eff = id;
var_nature_eff = SyntaxTreeCore.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;
}
in
Hashtbl.add node_env.lenv_vars id var;
var
(********************************************************************************)
(* A small util function followed by a quick unit test. *)
let rec fill i size = if i >= size then [] else i::(fill (i+1) size)
let _ = assert (fill 0 5 = [0;1;2;3;4])
let (elt_type_of_array : Eff.type_ list -> Eff.type_) =
function
| [Array_type_eff(t, _)] -> t
| _ -> assert false (* it ougth to be an array... *)
let rec (list_map3:
('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list) =
fun f l1 l2 l3 ->
match (l1, l2, l3) with
| ([], [], []) -> []
| (e1::t1, e2::t2, e3::t3) -> (f e1 e2 e3)::(list_map3 f t1 t2 t3)
| _ -> (* should not occur *)
print_string "*** list_map3 called with lists of different size.\n";
flush stdout;
assert false
let (check_clock_and_type :
Eff.id_solver -> Lxm.t -> val_exp -> Eff.type_ -> Eff.id_clock -> unit) =
fun id_solver lxm rhs exp_type (_,exp_clock) ->
(* Let's be paranoiac and check types and clocks of the expression
this function generates.
Moreover, this fills some tables that may be used by
the call to Split.eq below....*)
let rhs, rhs_tl = EvalType.f id_solver rhs in
if (rhs_tl <> [exp_type]) then assert false;
try ignore(EvalClock.f lxm id_solver UnifyClock.empty_subst rhs [exp_clock])
with _ -> assert false
(********************************************************************************)
(* The functions below accumulate
(1) the new equations
(2) the fresh variables.
*)
type inline_acc = (Eff.eq_info srcflagged) list * Eff.var_info list
let rec (inline_eq: Eff.local_env ->
Eff.id_solver -> inline_acc -> Eff.eq_info srcflagged -> inline_acc) =
fun node_env id_solver (eqs, locs) eq ->
let { src = lxm_eq ; it = (lhs, rhs) } = eq in
match rhs.core with
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "map"),sargs)}})},
OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.Map, sargs)}, OperEff args)
->
(* Given
- a node n of type: tau_1 * ... * tau_n -> teta_1 * ... * teta_l
- and an integer c
The profile of map<<node,c>> is:
tau_1^c * ... * tau_n^c -> teta_1^c * ... * teta_l^c
and
Y1, ... ,Yl = map<<node; c>>(X1,...,Xk)
<=>
for all i = 0, ..., c-1; (Y1[i], ... ,Yl[i]) = N(X_1[i], ... ,X_k[i])
*)
Erwan Jahier
committed
let ((node,inlist,outlist),c) = match sargs with
| [ConstStaticArgEff(_,Int_const_eff(c)) ; NodeStaticArgEff(_,node)]
| [NodeStaticArgEff(_,node) ; ConstStaticArgEff(_,Int_const_eff(c))] ->
node, c
| _ -> assert false (* todo: issue an error *)
in
Erwan Jahier
committed
let node = id_solver.id2node (Ident.idref_of_long node) [] lxm_ve in
let node = flagit node lxm_ve in
let index_list = fill 0 c in
List.fold_left
(fun (eqs,locs) i ->
let lhs = List.map
(fun lp ->
let t_elt = elt_type_of_array [type_of_left lp] in
LeftArrayEff(lp, i, t_elt))
lhs
in
let args =
List.map
(fun arg ->
let targ = arg.typ in
let t_elt = elt_type_of_array targ in
let op_flg = { src = lxm_ve ; it = ARRAY_ACCES(i) } in
let narg = {
core = CallByPosEff(op_flg, OperEff [arg]);
typ = [t_elt];
clk = arg.clk
}
in
Erwan Jahier
committed
narg
)
let nrhs = { rhs with core =
CallByPosEff({ src = lxm_ve ; it = (CALL node)}, OperEff args) }
Erwan Jahier
committed
let eq = { src = lxm_eq ; it = (lhs, nrhs) } in
(eq::eqs,locs)
)
(eqs,locs)
index_list
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "red"),sargs)}})},
OperEff args)
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "fill"),sargs)}})},
OperEff args)
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "fillred"),sargs)}})},
OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.Fill, sargs)}, OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.Red, sargs)}, OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.FillRed,sargs)}, OperEff args)
->
(* Given
- a node n of type
tau * tau_1 * ... * tau_n -> tau * teta_1 * ... * teta_l
- a integer c
the fillred expression has the profile:
tau * tau_1^c * ... * tau_n^c -> tau * teta_1^c * ... * teta_l^c
acc_out, Y1, ... ,Yl = fillred<<node; c>>(acc_in,X1,...,Xk)
<=>
exists acc_0, ..., acc_c-1, where acc_o=acc_in, and acc_c-1=acc_out
such that, for all i = 0, ..., c-1;
(acc_i+1, Y1[i], ... ,Yl[i]) = N(acc_i,X_1[i], ... ,X_k[i])
Erwan Jahier
committed
let ((node,_,_),c) = match sargs with
| [ConstStaticArgEff(_,Int_const_eff(c)) ; NodeStaticArgEff(_,node)]
| [NodeStaticArgEff(_,node) ; ConstStaticArgEff(_,Int_const_eff(c))] ->
node, c
| _ -> assert false (* todo: issue an error *)
in
Erwan Jahier
committed
let node = id_solver.id2node (Ident.idref_of_long node) [] lxm_ve in
let node = flagit node lxm_ve in
let index_list = fill 0 c in
(* Retreive acc_in and acc_out *)
let acc_out = List.hd lhs in
let lhs = List.tl lhs in
let acc_in = List.hd args in
let args = List.tl args in
List.hd (acc_in.typ),
List.hd (acc_in.clk)
let rec f i acc =
f (i-1) ((new_var "acc" node_env type_exp clock_exp)::acc)
in
(* coquetry: reverse the list to have the name in a nice order *)
List.rev(f (c-1) [])
in
let (acc_left_list : left list) =
(List.map (fun vi -> LeftVarEff(vi,lxm_ve)) acc_vars)@[acc_out]
in
let (acc_rigth_list : val_exp list) =
acc_in::(
let id = Ident.to_idref vi.var_name_eff in
let op_flg = { src = lxm_ve ; it = IDENT id } in
let ve = {
typ = [vi.var_type_eff];
clk = [snd vi.var_clock_eff];
core = CallByPosEff(op_flg, OperEff []) }
in
Erwan Jahier
committed
ve
)
acc_vars)
in
let neqs =
list_map3
(fun i acc_left acc_rigth ->
let args =
List.map
(fun arg ->
let t_elt = elt_type_of_array arg.typ in
let op_flg = {src = lxm_ve ; it = ARRAY_ACCES(i)} in
let new_arg =
{ core = CallByPosEff(op_flg, OperEff [arg]);
typ=[t_elt];
clk=[clock_exp];
}
new_arg
)
args
in
let args = acc_rigth::args in
let lhs =
List.map
(fun lp ->
let t_elt = elt_type_of_array [type_of_left lp] in
LeftArrayEff(lp,i,t_elt))
lhs
in
let lhs = acc_left::lhs in
Erwan Jahier
committed
let tl = List.map Eff.type_of_left lhs in
let cl = List.map
(fun l -> (Eff.var_info_of_left l).var_clock_eff) lhs
in
let rhs = {
typ = tl;
clk = List.map snd cl;
core = CallByPosEff({src=lxm_ve;it = (CALL node)}, OperEff args) }
let eq = { src = lxm_eq ; it = (lhs, rhs) } in
eq
)
index_list
acc_left_list
acc_rigth_list
in
(List.rev_append neqs eqs, List.append acc_vars locs)
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "diese"),_)}})},
OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.DIESE_n,_)}, OperEff args) ->
(* a diese is a particular kind of boolred:
#(A,...,an) = boolred(1,1,n)([a1,...,an])
*)
let clk = rhs.clk in
let n = List.length args in
let sargs = [ConstStaticArgEff(Ident.of_string "i",Int_const_eff 1);
ConstStaticArgEff(Ident.of_string "j",Int_const_eff 1);
ConstStaticArgEff(Ident.of_string "k",Int_const_eff n)
]
in
let boolred_op = Eff.Predef(Predef.BoolRed,sargs) in
let arg = {
typ = [Array_type_eff(Bool_type_eff,n) ];
clk = clk;
core = CallByPosEff({src=lxm_ve;it= ARRAY args}, OperEff [])} in
let rhs = {
typ = [Bool_type_eff];
clk = clk;
core = CallByPosEff({src=lxm_ve;it=boolred_op}, OperEff [arg]) }
in
let eq = { src = lxm_eq ; it = (lhs, rhs) } in
inline_eq node_env id_solver (eqs, locs) eq
| CallByPosEff(
{src=lxm_ve;it=CALL ({it = {node_key_eff = (("Lustre", "nor"),_)}})},
OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.NOR_n,_)}, OperEff args) ->
(* a nor is a particular kind of boolred too:
#(A,...,an) = boolred(0,0,n)([a1,...,an])
*)
let clk = rhs.clk in
let n = List.length args in
let sargs = [ConstStaticArgEff(Ident.of_string "i",Int_const_eff 0);
ConstStaticArgEff(Ident.of_string "j",Int_const_eff 0);
ConstStaticArgEff(Ident.of_string "k",Int_const_eff n)
]
in
let boolred_op = Eff.Predef(Predef.BoolRed,sargs) in
let arg = {
typ = [Array_type_eff(Bool_type_eff,n) ];
clk = clk;
core = CallByPosEff({src=lxm_ve;it=ARRAY args}, OperEff []) }
in
let rhs = {
typ = [Bool_type_eff];
clk = clk;
core = CallByPosEff({src=lxm_ve;it=boolred_op}, OperEff [arg]) }
in
Erwan Jahier
committed
let eq = { src = lxm_eq ; it = (lhs, rhs) } in
inline_eq node_env id_solver (eqs, locs) eq
| CallByPosEff({src=lxm_ve;it=CALL (
{it = {node_key_eff = (("Lustre", "boolred"),sargs)}})},
OperEff args)
| CallByPosEff({src=lxm_ve;it=Eff.Predef(Predef.BoolRed,sargs)}, OperEff args) ->
(* Given
- 3 integers i, j, k
boolref<<i,j,k>> has the profile: bool^n -> bool
and
res = boolred<<i,j,k>>(A);
cpt = (if A[0] then 1 else 0) + ... + (if A[k-1] then 1 else 0);
res = i <= cpt && cpt <= j;
*)
let rhs_clk = rhs.clk in
let (i,j,k) =
match sargs with
| [ConstStaticArgEff(_,Int_const_eff i);
ConstStaticArgEff(_,Int_const_eff j);
ConstStaticArgEff(_,Int_const_eff k)
] ->
(i,j,k)
| _ -> assert false
in
let index_list = fill 0 k in
let lp = try List.hd lhs with Not_found -> assert false in
let res_clock = (Eff.var_info_of_left lp).var_clock_eff in
let cpt = new_var "cpt" node_env Int_type_eff (snd res_clock) in
let id_of_int i = Predef.ICONST_n(Ident.of_string (string_of_int i)) in
let rhs = (* i <= cpt && cpt <= j; *)
let i_op = { it = Predef(id_of_int i,[]) ; src = lxm_ve }
and j_op = { it = Predef(id_of_int j,[]) ; src = lxm_ve }
and cpt_op = { it = IDENT (Ident.to_idref cpt.var_name_eff);src=lxm_ve }
and and_op = { it = Predef(Predef.AND_n,[]) ; src = lxm_ve }
and inf_op = { it = Predef(Predef.LTE_n,[]) ; src = lxm_ve } in
let i_eff = { clk=rhs_clk; typ = [Int_type_eff]; core = CallByPosEff(i_op, OperEff []) }
and j_eff = { clk=rhs_clk; typ = [Int_type_eff]; core = CallByPosEff(j_op, OperEff [])}
and cpt_eff = { clk=rhs_clk; typ = [Int_type_eff]; core = CallByPosEff(cpt_op, OperEff []) }
let i_inf_cpt = { clk=rhs_clk; typ = [Bool_type_eff];
core = CallByPosEff(inf_op,OperEff[i_eff;cpt_eff]) }
and cpt_if_j = { clk=rhs_clk; typ = [Bool_type_eff];
core = CallByPosEff(inf_op,OperEff[cpt_eff;j_eff]) }
in
{ clk=rhs_clk; typ = [Bool_type_eff];
core = CallByPosEff(and_op, OperEff [i_inf_cpt; cpt_if_j]) }
in
let eq =
check_clock_and_type id_solver lxm_eq rhs Bool_type_eff res_clock;
{ src = lxm_eq ; it = (lhs, rhs) }
in
let eq_cpt =
let lhs = [LeftVarEff(cpt,lxm_ve)] in
(* (if A[0] then 1 else 0) + ... + (if A[k-1] then 1 else 0) *)
let zero = {
clk = rhs_clk; typ = [Int_type_eff];
core = CallByPosEff({it=Predef(id_of_int 0,[]);src=lxm_ve},OperEff[])}
and one = {
clk = rhs_clk;
typ = [Int_type_eff];
core = CallByPosEff({it=Predef(id_of_int 1,[]);src=lxm_ve},OperEff[]) }
and plus_op = { it = Predef(Predef.IPLUS_n,[]) ; src = lxm_ve }
and ite_op = { it = Predef(Predef.IF_n,[]) ; src = lxm_ve }
in
let array, type_elt =
match args with
| [arg] -> arg,elt_type_of_array arg.typ
| _ -> assert false
in
let make_ite i = (* returns '(if A[i] then 1 else 0)' *)
let a_op = { it = ARRAY_ACCES(i) ; src = lxm_ve } in
let a_i = { clk = rhs_clk; typ = [type_elt];
core = CallByPosEff(a_op, OperEff [array]) }
in
let nve = {
clk=rhs_clk; typ = [Int_type_eff];
core = CallByPosEff(ite_op, OperEff [a_i;one;zero]) }
in
let rhs =
List.fold_left
Erwan Jahier
committed
(fun acc i ->
let nve = {
clk=rhs_clk; typ = [Int_type_eff];
core = CallByPosEff(plus_op, OperEff [acc; make_ite i]) }
in
Erwan Jahier
committed
nve
)
(make_ite (List.hd index_list))
(List.tl index_list)
in
check_clock_and_type id_solver lxm_eq rhs Int_type_eff res_clock;
{ src = lxm_eq ; it = (lhs, rhs) }
in
if !Global.one_op_per_equation then
let eqs_res, vars_res = Split.eq node_env eq in
let eqs_cpt, vars_cpt = Split.eq node_env eq_cpt in
let eqs = List.rev_append (eqs_res@eqs_cpt) eqs
and locs = cpt::(List.append vars_res (List.append vars_cpt locs))
in
(eqs, locs)
else
(eq::eq_cpt::eqs, cpt::locs)
(* All the other operators *)
| _ ->
(eq::eqs, locs)
(* exported *)
and (iterators : Eff.local_env -> Eff.id_solver -> Eff.node_exp -> Eff.node_exp) =
fun node_env id_solver n ->
match n.def_eff with
| ExternEff
| AbstractEff None -> n
| AbstractEff (Some pn) ->
{ n with def_eff = AbstractEff (Some (iterators node_env id_solver pn)) }
| BodyEff b ->
Name.reset_local_var_prefix "acc";
Name.reset_local_var_prefix "cpt";
let nv = match n.loclist_eff with None -> [] | Some l -> l in
let (neqs, nv) =
List.fold_left (inline_eq node_env id_solver) ([], nv) b.eqs_eff