(* Time-stamp: <modified the 06/03/2020 (at 13:36) by Erwan Jahier> *) open Soc2cUtil open Soc2cIdent open Soc let (mem_interface_out : Soc.t -> string -> bool) = fun soc id -> let _,outs = soc.profile in List.mem_assoc id outs let (not_an_array : Data.t -> bool) = function | Data.Array(_,_) -> false | _ -> true let (ve_not_an_array : Soc.var_expr -> bool) = fun v -> match v with | Var(_,t) | Const(_,t) | Field(_,_,t) | Index(_,_,t) -> not_an_array t | Slice(_,_,_,_,_,_) -> false let (ve_not_a_field : Soc.var_expr -> bool) = fun v -> match v with | Var(_,_) | Const(_,_) | Index(_,_,_) | Slice(_,_,_,_,_,_) -> true | Field(_,_,_t) -> false (* exported : returns true if v is an output of soc *) let rec (is_soc_output : Soc.var_expr -> Soc.t -> bool) = fun v soc -> match v with | Var(n,t) -> List.mem (n,t) (snd soc.profile) | Const(_) -> false | Index(ve,_,_t) | Field(ve,_,_t) | Slice(ve,_,_,_,_,_t) -> is_soc_output ve soc let (is_soc_output_and_not_a_struct : Soc.var_expr -> Soc.t -> bool) = fun v soc -> match v with | Var(n,t) -> List.mem (n,t) (snd soc.profile) | Const(_) -> false | Index(_ve,_,_t) | Field(_ve,_,_t) | Slice(_ve,_,_,_,_,_t) -> false (* is_soc_output_and_not_a_struct ve soc *) let rec (string_of_var_expr: Soc.t -> Soc.var_expr -> string) = fun soc var -> match var with | Const("true", _) -> "_true" | Const("false", _) -> "_false" | Const(id, _) -> id2s id | Var ("_memory",_) -> (* Clutch! it's not an interface var... *) "ctx->_memory" | Var (id,_t) -> id2s id | Field(f, id,_) -> if is_soc_output_and_not_a_struct f soc then Printf.sprintf "%s->%s" (string_of_var_expr soc f) (id2s id) else Printf.sprintf "%s.%s" (string_of_var_expr soc f) (id2s id) | Index(f, index,_) -> Printf.sprintf "%s[%i]" (string_of_var_expr soc f) index | Slice(_f,_fi,_la,_st,_wi,_vt) -> assert false (* should not occur *) (* exported *) let rec (gen_assign : Data.t -> string -> string -> string) = fun t vi vo -> let t_str = Soc2cUtil.data_type_to_c t "" in match t with | Data.Alias(_,t) -> gen_assign t vi vo | Data.Enum _ | Data.Struct(_) (* should I rather use memcpy for struct? *) | Data.Bool | Data.Int | Data.Real -> Printf.sprintf " %s = %s;\n" vi vo | Data.Alpha(_) (* dead code ? *) | Data.String | Data.Array(_) -> let t_str_short = Soc2cIdent.type_to_short_string t in Printf.sprintf " _assign_%s(%s, %s, sizeof(%s));\n" t_str_short vi vo t_str | Data.Extern (id) -> Printf.sprintf " _assign_%s(%s, %s, sizeof(%s));\n" (id2s id) vi vo t_str let (gen_assign_var_expr : Soc.t -> Soc.var_expr -> Soc.var_expr -> string) = fun soc vo vi -> match vo,vi with | Slice _, _ | _, Slice _ -> assert false | _,_ -> let left = string_of_var_expr soc vo in let left = if is_soc_output_and_not_a_struct vo soc && ve_not_an_array vo && ve_not_a_field vo then "*"^left else left in let vi_str = string_of_var_expr soc vi in let vi_str = if is_soc_output_and_not_a_struct vi soc && ve_not_an_array vi then "*"^vi_str else vi_str in gen_assign (Soc.data_type_of_var_expr vo) left vi_str let (step_name : Soc.key -> string -> string) = fun sk sm -> let str = Printf.sprintf "%s_%s" (Soc2cIdent.get_soc_name sk) sm in (* Printf.printf " XXX step_name(%s)=%s\n" (SocUtils.string_of_soc_key sk) str; *) (* flush stdout; *) (id2s str) let (ctx_var : var_kind -> Soc.t -> Lv6Id.t -> string) = fun _opt soc id -> if mem_interface_out soc id then Printf.sprintf "*%s" (id2s id) else Printf.sprintf "%s" (id2s id) let (list_split : 'a list -> int -> 'a list * 'a list) = fun l s -> let rec aux s l acc = match s,l with | 0, _ -> List.rev acc,l | _, x::l -> aux (s-1) l (x::acc) | _, [] -> assert false in aux s l [] let _ = assert (list_split [1;2;3;4;5;6] 3 = ([1;2;3],[4;5;6])) let (inline_soc: Soc.t -> Soc.t -> Soc.var_expr list -> Soc.var_expr list -> string option) = fun soc called_soc vel_out vel_in -> let called_soc_name,_,_ = called_soc.key in match called_soc_name with (* those soc are inlined. Currently we only inline ite because of its polymorphism. Simple arith operators (+,-,*,/,etc.) should be inlined too. *) | "Lustre::if" -> let c,vel_in= match vel_in with [] -> assert false | c::l -> c,l in let s = (List.length vel_out) in let vel_in_t, vel_in_e = list_split vel_in s in let lt = List.map2 (gen_assign_var_expr soc) vel_out vel_in_t in let le = List.map2 (gen_assign_var_expr soc) vel_out vel_in_e in let ptr_indir = if is_soc_output_and_not_a_struct c soc then "*" else "" in let str = " if ("^ ptr_indir^string_of_var_expr soc c ^" == _true) {\n "^ (String.concat " " lt)^ " } else {\n "^ (String.concat " " le)^ " }\n" in Some str | _ -> try if Lv6MainArgs.global_opt.Lv6MainArgs.gen_c_inline_predef && Soc2cPredef.is_call_supported called_soc.key then let vel_in_str = List.map (string_of_var_expr soc) vel_in in let vel_in = List.map2 (fun v s -> if is_soc_output_and_not_a_struct v soc && ve_not_an_array v then "*"^s else s) vel_in vel_in_str in let vel_out_str = List.map (string_of_var_expr soc) vel_out in let vel_out = List.map2 (fun v s -> if is_soc_output_and_not_a_struct v soc && ve_not_an_array v then "*"^s else s) vel_out vel_out_str in Some (Soc2cPredef.gen_call called_soc.key soc vel_out vel_in) else None with Not_found -> (* Printf.eprintf "won't inline %s\n" called_soc_name; *) None (* exported *) let (inlined_soc : Soc.key -> bool) = fun key -> let soc_name,_,_ = key in soc_name = "Lustre::if" || Soc2cPredef.is_call_supported key (* exported *) let (gen_step_call : Soc.t -> Soc.t -> Soc.var_expr list -> Soc.var_expr list -> string -> string -> string -> string) = fun soc called_soc vel_out vel_in _ctx sname step_arg -> match inline_soc soc called_soc vel_out vel_in with | Some str -> str | None -> let vel_in_str = List.map (string_of_var_expr soc) vel_in in let vel_in = List.map2 (fun v s -> if is_soc_output_and_not_a_struct v soc && ve_not_an_array v then "*"^s else s) vel_in vel_in_str in let vel_out_str = List.map (string_of_var_expr soc) vel_out in let vel_out = List.map2 (fun v s -> if (not (is_soc_output_and_not_a_struct v soc) && ve_not_an_array v ) then "&"^s else s) vel_out vel_out_str in let step_arg = if step_arg = "" then [] else [step_arg] in let step_arg = String.concat "," (vel_in@vel_out@step_arg) in let str = Printf.sprintf " %s(%s); \n" (step_name called_soc.key sname) step_arg in str (* exported *) let (typedef_of_soc : Soc.t -> string) = fun soc -> if inlined_soc soc.key then "" (* don't generate code if inlined *) else if SocUtils.is_memory_less soc then "" else let ctx_name = get_ctx_name soc.key in let ctx_name_type = ctx_name^"_type" in let str = Printf.sprintf "/* %s */\ntypedef struct {\n" ctx_name in let str = str ^ (match soc.memory with | No_mem -> "" | Mem t -> Printf.sprintf " /*Memory cell*/\n %s ;\n" (id2s (Soc2cUtil.data_type_to_c t "_memory")) | Mem_hidden -> "" ) in let str = str ^ (if soc.instances <> [] then " /*INSTANCES*/\n" else "") in let il, _get_index = Soc2cInstances.to_array soc.instances in let string_of_instance (sk,i) = let n = get_ctx_name sk in Printf.sprintf " %s_type %s_tab[%d];\n" n n i in let str = List.fold_left (fun acc inst -> acc^(string_of_instance inst)) str il in let str = Printf.sprintf "%s} %s;\n\n" str ctx_name_type in str (* exported *) (* for soc of type (int * int -> int), it generates something like "void step(int, int, int*, soc_ctx_type* );", "void step(int x, int y, int* res, soc_ctx_type* ctx){" *) let (get_step_prototype : Soc.step_method -> Soc.t -> string * string * string) = fun sm soc -> let sname = step_name soc.key sm.name in let inputs, outputs = soc.Soc.profile in let inputs = SocUtils.filter_step_params sm.Soc.idx_ins inputs in let outputs = SocUtils.filter_step_params sm.Soc.idx_outs outputs in let to_param_decl is_an_output (_id,dt) = match is_an_output, dt with | true, Data.Array(_,_) -> Soc2cUtil.data_type_to_c dt "" ^"/*out*/" (* arrays are already pointers... *) | false, _ -> Soc2cUtil.data_type_to_c dt "" | true, _ -> Soc2cUtil.data_type_to_c dt "*" in let to_param out (id,dt) = match out, dt with | true, Data.Array(_,_) -> Soc2cUtil.data_type_to_c dt id ^"/*out*/" | false, _ -> Soc2cUtil.data_type_to_c dt id | true, _ -> Soc2cUtil.data_type_to_c dt ("*"^id) in let in_params = List.map (to_param false) inputs in let out_params = List.map (to_param true) outputs in let in_params_decl = List.map (to_param_decl false) inputs in let out_params_decl = List.map (to_param_decl true) outputs in let params = String.concat "," (in_params@out_params) in let params_decl = String.concat "," (in_params_decl@out_params_decl) in let ctype = match inputs with | (_,t)::_ -> Printf.sprintf "sizeof(%s)" (Soc2cUtil.data_type_to_c t "") | [] -> "" (* soc without intputs won't need this output *) in if SocUtils.is_memory_less soc then Printf.sprintf "void %s(%s);\n" sname params_decl, Printf.sprintf "void %s(%s){\n" sname params, ctype else let ctx = Printf.sprintf "%s_type* ctx" (get_ctx_name soc.key) in let ctx_decl = Printf.sprintf "%s_type*" (get_ctx_name soc.key) in Printf.sprintf "void %s(%s,%s);\n" sname params_decl ctx_decl, Printf.sprintf "void %s(%s,%s){" sname params ctx, ctype