1

(********************************************************************)

2

(* *)

3

(* The LustreC compiler toolset / The LustreC Development Team *)

4

(* Copyright 2012   ONERA  CNRS  INPT *)

5

(* *)

6

(* LustreC is free software, distributed WITHOUT ANY WARRANTY *)

7

(* under the terms of the GNU Lesser General Public License *)

8

(* version 2.1. *)

9

(* *)

10

(********************************************************************)

11


12

open LustreSpec

13

open Corelang

14

open Clocks

15

open Causality

16


17

exception NormalizationError

18


19

module OrdVarDecl:Map.OrderedType with type t=var_decl =

20

struct type t = var_decl;; let compare = compare end

21


22

module ISet = Set.Make(OrdVarDecl)

23


24

type value_t =

25

 Cst of constant

26

 LocalVar of var_decl

27

 StateVar of var_decl

28

 Fun of ident * value_t list

29

 Array of value_t list

30

 Access of value_t * value_t

31

 Power of value_t * value_t

32


33

type instr_t =

34

 MLocalAssign of var_decl * value_t

35

 MStateAssign of var_decl * value_t

36

 MReset of ident

37

 MStep of var_decl list * ident * value_t list

38

 MBranch of value_t * (label * instr_t list) list

39


40

let rec pp_val fmt v =

41

match v with

42

 Cst c > Printers.pp_const fmt c

43

 LocalVar v > Format.pp_print_string fmt v.var_id

44

 StateVar v > Format.pp_print_string fmt v.var_id

45

 Array vl > Format.fprintf fmt "[%a]" (Utils.fprintf_list ~sep:", " pp_val) vl

46

 Access (t, i) > Format.fprintf fmt "%a[%a]" pp_val t pp_val i

47

 Power (v, n) > Format.fprintf fmt "(%a^%a)" pp_val v pp_val n

48

 Fun (n, vl) > Format.fprintf fmt "%s (%a)" n (Utils.fprintf_list ~sep:", " pp_val) vl

49


50

let rec pp_instr fmt i =

51

match i with

52

 MLocalAssign (i,v) > Format.fprintf fmt "%s<l %a" i.var_id pp_val v

53

 MStateAssign (i,v) > Format.fprintf fmt "%s<s %a" i.var_id pp_val v

54

 MReset i > Format.fprintf fmt "reset %s" i

55

 MStep (il, i, vl) >

56

Format.fprintf fmt "%a = %s (%a)"

57

(Utils.fprintf_list ~sep:", " (fun fmt v > Format.pp_print_string fmt v.var_id)) il

58

i

59

(Utils.fprintf_list ~sep:", " pp_val) vl

60

 MBranch (g,hl) >

61

Format.fprintf fmt "@[<v 2>case(%a) {@,%a@,}@]"

62

pp_val g

63

(Utils.fprintf_list ~sep:"@," pp_branch) hl

64


65

and pp_branch fmt (t, h) =

66

Format.fprintf fmt "@[<v 2>%s:@,%a@]" t (Utils.fprintf_list ~sep:"@," pp_instr) h

67


68

type step_t = {

69

step_checks: (Location.t * value_t) list;

70

step_inputs: var_decl list;

71

step_outputs: var_decl list;

72

step_locals: var_decl list;

73

step_instrs: instr_t list;

74

step_asserts: value_t list;

75

}

76


77

type static_call = top_decl * (Dimension.dim_expr list)

78


79

type machine_t = {

80

mname: node_desc;

81

mmemory: var_decl list;

82

mcalls: (ident * static_call) list; (* map from stateful/stateless instance to node, no internals *)

83

minstances: (ident * static_call) list; (* submap of mcalls, from stateful instance to node *)

84

minit: instr_t list;

85

mstatic: var_decl list; (* static inputs only *)

86

mstep: step_t;

87

mspec: node_annot option;

88

mannot: expr_annot list;

89

}

90


91

let pp_step fmt s =

92

Format.fprintf fmt "@[<v>inputs : %a@ outputs: %a@ locals : %a@ checks : %a@ instrs : @[%a@]@ asserts : @[%a@]@]@ "

93

(Utils.fprintf_list ~sep:", " Printers.pp_var) s.step_inputs

94

(Utils.fprintf_list ~sep:", " Printers.pp_var) s.step_outputs

95

(Utils.fprintf_list ~sep:", " Printers.pp_var) s.step_locals

96

(Utils.fprintf_list ~sep:", " (fun fmt (_, c) > pp_val fmt c)) s.step_checks

97

(Utils.fprintf_list ~sep:"@ " pp_instr) s.step_instrs

98

(Utils.fprintf_list ~sep:", " pp_val) s.step_asserts

99


100


101

let pp_static_call fmt (node, args) =

102

Format.fprintf fmt "%s<%a>"

103

(node_name node)

104

(Utils.fprintf_list ~sep:", " Dimension.pp_dimension) args

105


106

let pp_machine fmt m =

107

Format.fprintf fmt

108

"@[<v 2>machine %s@ mem : %a@ instances: %a@ init : %a@ step :@ @[<v 2>%a@]@ @ spec : @[%t@]@ annot : @[%a@]@]@ "

109

m.mname.node_id

110

(Utils.fprintf_list ~sep:", " Printers.pp_var) m.mmemory

111

(Utils.fprintf_list ~sep:", " (fun fmt (o1, o2) > Format.fprintf fmt "(%s, %a)" o1 pp_static_call o2)) m.minstances

112

(Utils.fprintf_list ~sep:"@ " pp_instr) m.minit

113

pp_step m.mstep

114

(fun fmt > match m.mspec with  None > ()  Some spec > Printers.pp_spec fmt spec)

115

(Utils.fprintf_list ~sep:"@ " Printers.pp_expr_annot) m.mannot

116


117

(* Returns the declared stateless status and the computed one. *)

118

let get_stateless_status m =

119

(m.mname.node_dec_stateless, Utils.desome m.mname.node_stateless)

120


121

let is_input m id =

122

List.exists (fun o > o.var_id = id.var_id) m.mstep.step_inputs

123


124

let is_output m id =

125

List.exists (fun o > o.var_id = id.var_id) m.mstep.step_outputs

126


127

let is_memory m id =

128

List.exists (fun o > o.var_id = id.var_id) m.mmemory

129


130

let conditional c t e =

131

MBranch(c, [ (tag_true, t); (tag_false, e) ])

132


133

let dummy_var_decl name typ =

134

{

135

var_id = name;

136

var_orig = false;

137

var_dec_type = dummy_type_dec;

138

var_dec_clock = dummy_clock_dec;

139

var_dec_const = false;

140

var_type = typ;

141

var_clock = Clocks.new_ck (Clocks.Cvar Clocks.CSet_all) true;

142

var_loc = Location.dummy_loc

143

}

144


145

let arrow_id = "_arrow"

146


147

let arrow_typ = Types.new_ty Types.Tunivar

148


149

let arrow_desc =

150

{

151

node_id = arrow_id;

152

node_type = Type_predef.type_bin_poly_op;

153

node_clock = Clock_predef.ck_bin_univ;

154

node_inputs= [dummy_var_decl "_in1" arrow_typ; dummy_var_decl "_in2" arrow_typ];

155

node_outputs= [dummy_var_decl "_out" arrow_typ];

156

node_locals= [];

157

node_gencalls = [];

158

node_checks = [];

159

node_asserts = [];

160

node_stmts= [];

161

node_dec_stateless = false;

162

node_stateless = Some false;

163

node_spec = None;

164

node_annot = []; }

165


166

let arrow_top_decl =

167

{

168

top_decl_desc = Node arrow_desc;

169

top_decl_owner = Version.prefix;

170

top_decl_itf = false;

171

top_decl_loc = Location.dummy_loc

172

}

173


174

let arrow_machine =

175

let state = "_first" in

176

let var_state = dummy_var_decl state (Types.new_ty Types.Tbool) in

177

let var_input1 = List.nth arrow_desc.node_inputs 0 in

178

let var_input2 = List.nth arrow_desc.node_inputs 1 in

179

let var_output = List.nth arrow_desc.node_outputs 0 in

180

{

181

mname = arrow_desc;

182

mmemory = [var_state];

183

mcalls = [];

184

minstances = [];

185

minit = [MStateAssign(var_state, Cst (const_of_bool true))];

186

mstatic = [];

187

mstep = {

188

step_inputs = arrow_desc.node_inputs;

189

step_outputs = arrow_desc.node_outputs;

190

step_locals = [];

191

step_checks = [];

192

step_instrs = [conditional (StateVar var_state)

193

[MStateAssign(var_state, Cst (const_of_bool false));

194

MLocalAssign(var_output, LocalVar var_input1)]

195

[MLocalAssign(var_output, LocalVar var_input2)] ];

196

step_asserts = [];

197

};

198

mspec = None;

199

mannot = [];

200

}

201


202

let new_instance =

203

let cpt = ref (1) in

204

fun caller callee tag >

205

begin

206

let o =

207

if Stateless.check_node callee then

208

node_name callee

209

else

210

Printf.sprintf "ni_%d" (incr cpt; !cpt) in

211

let o =

212

if !Options.ansi && is_generic_node callee

213

then Printf.sprintf "%s_inst_%d" o (Utils.position (fun e > e.expr_tag = tag) caller.node_gencalls)

214

else o in

215

o

216

end

217


218

(* translate_<foo> : node > context > <foo> > machine code/expression *)

219

(* the context contains m : state aka memory variables *)

220

(* si : initialization instructions *)

221

(* j : node aka machine instances *)

222

(* d : local variables *)

223

(* s : step instructions *)

224

let translate_ident node (m, si, j, d, s) id =

225

try (* id is a node var *)

226

let var_id = get_node_var id node in

227

if ISet.exists (fun v > v.var_id = id) m

228

then StateVar var_id

229

else LocalVar var_id

230

with Not_found >

231

try (* id is a constant *)

232

LocalVar (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id)))

233

with Not_found >

234

(* id is a tag *)

235

Cst (Const_tag id)

236


237

let rec control_on_clock node ((m, si, j, d, s) as args) ck inst =

238

match (Clocks.repr ck).cdesc with

239

 Con (ck1, cr, l) >

240

let id = Clocks.const_of_carrier cr in

241

control_on_clock node args ck1 (MBranch (translate_ident node args id,

242

[l, [inst]] ))

243

 _ > inst

244


245

let rec join_branches hl1 hl2 =

246

match hl1, hl2 with

247

 [] , _ > hl2

248

 _ , [] > hl1

249

 (t1, h1)::q1, (t2, h2)::q2 >

250

if t1 < t2 then (t1, h1) :: join_branches q1 hl2 else

251

if t1 > t2 then (t2, h2) :: join_branches hl1 q2

252

else (t1, List.fold_right join_guards h1 h2) :: join_branches q1 q2

253


254

and join_guards inst1 insts2 =

255

match inst1, insts2 with

256

 _ , [] >

257

[inst1]

258

 MBranch (x1, hl1), MBranch (x2, hl2) :: q when x1 = x2 >

259

MBranch (x1, join_branches (sort_handlers hl1) (sort_handlers hl2))

260

:: q

261

 _ > inst1 :: insts2

262


263

let join_guards_list insts =

264

List.fold_right join_guards insts []

265


266

(* specialize predefined (polymorphic) operators

267

wrt their instances, so that the C semantics

268

is preserved *)

269

let specialize_to_c expr =

270

match expr.expr_desc with

271

 Expr_appl (id, e, r) >

272

if List.exists (fun e > Types.is_bool_type e.expr_type) (expr_list_of_expr e)

273

then let id =

274

match id with

275

 "=" > "equi"

276

 "!=" > "xor"

277

 _ > id in

278

{ expr with expr_desc = Expr_appl (id, e, r) }

279

else expr

280

 _ > expr

281


282

let specialize_op expr =

283

match !Options.output with

284

 "C" > specialize_to_c expr

285

 _ > expr

286


287

let rec translate_expr node ((m, si, j, d, s) as args) expr =

288

let expr = specialize_op expr in

289

match expr.expr_desc with

290

 Expr_const v > Cst v

291

 Expr_ident x > translate_ident node args x

292

 Expr_array el > Array (List.map (translate_expr node args) el)

293

 Expr_access (t, i) > Access (translate_expr node args t, translate_expr node args (expr_of_dimension i))

294

 Expr_power (e, n) > Power (translate_expr node args e, translate_expr node args (expr_of_dimension n))

295

 Expr_tuple _

296

 Expr_arrow _

297

 Expr_fby _

298

 Expr_pre _ > (Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError)

299

 Expr_when (e1, _, _) > translate_expr node args e1

300

 Expr_merge (x, _) > raise NormalizationError

301

 Expr_appl (id, e, _) when Basic_library.is_internal_fun id >

302

let nd = node_from_name id in

303

Fun (node_name nd, List.map (translate_expr node args) (expr_list_of_expr e))

304

 Expr_ite (g,t,e) > (

305

(* special treatment depending on the active backend. For horn backend, ite

306

are preserved in expression. While they are removed for C or Java

307

backends. *)

308

match !Options.output with  "horn" >

309

Fun ("ite", [translate_expr node args g; translate_expr node args t; translate_expr node args e])

310

 "C"  "java"  _ >

311

(Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError)

312

)

313

 _ > raise NormalizationError

314


315

let translate_guard node args expr =

316

match expr.expr_desc with

317

 Expr_ident x > translate_ident node args x

318

 _ > (Format.eprintf "internal error: translate_guard %s %a@." node.node_id Printers.pp_expr expr;assert false)

319


320

let rec translate_act node ((m, si, j, d, s) as args) (y, expr) =

321

match expr.expr_desc with

322

 Expr_ite (c, t, e) > let g = translate_guard node args c in

323

conditional g [translate_act node args (y, t)]

324

[translate_act node args (y, e)]

325

 Expr_merge (x, hl) > MBranch (translate_ident node args x, List.map (fun (t, h) > t, [translate_act node args (y, h)]) hl)

326

 _ > MLocalAssign (y, translate_expr node args expr)

327


328

let reset_instance node args i r c =

329

match r with

330

 None > []

331

 Some r > let g = translate_guard node args r in

332

[control_on_clock node args c (conditional g [MReset i] [])]

333


334

let translate_eq node ((m, si, j, d, s) as args) eq =

335

(*Format.eprintf "translate_eq %a with clock %a@." Printers.pp_node_eq eq Clocks.print_ck eq.eq_rhs.expr_clock;*)

336

match eq.eq_lhs, eq.eq_rhs.expr_desc with

337

 [x], Expr_arrow (e1, e2) >

338

let var_x = get_node_var x node in

339

let o = new_instance node arrow_top_decl eq.eq_rhs.expr_tag in

340

let c1 = translate_expr node args e1 in

341

let c2 = translate_expr node args e2 in

342

(m,

343

MReset o :: si,

344

Utils.IMap.add o (arrow_top_decl, []) j,

345

d,

346

(control_on_clock node args eq.eq_rhs.expr_clock (MStep ([var_x], o, [c1;c2]))) :: s)

347

 [x], Expr_pre e1 when ISet.mem (get_node_var x node) d >

348

let var_x = get_node_var x node in

349

(ISet.add var_x m,

350

si,

351

j,

352

d,

353

control_on_clock node args eq.eq_rhs.expr_clock (MStateAssign (var_x, translate_expr node args e1)) :: s)

354

 [x], Expr_fby (e1, e2) when ISet.mem (get_node_var x node) d >

355

let var_x = get_node_var x node in

356

(ISet.add var_x m,

357

MStateAssign (var_x, translate_expr node args e1) :: si,

358

j,

359

d,

360

control_on_clock node args eq.eq_rhs.expr_clock (MStateAssign (var_x, translate_expr node args e2)) :: s)

361


362

 p , Expr_appl (f, arg, r) when not (Basic_library.is_internal_fun f) >

363

let var_p = List.map (fun v > get_node_var v node) p in

364

let el = expr_list_of_expr arg in

365

let vl = List.map (translate_expr node args) el in

366

let node_f = node_from_name f in

367

let call_f =

368

node_f,

369

NodeDep.filter_static_inputs (node_inputs node_f) el in

370

let o = new_instance node node_f eq.eq_rhs.expr_tag in

371

let env_cks = List.fold_right (fun arg cks > arg.expr_clock :: cks) el [eq.eq_rhs.expr_clock] in

372

let call_ck = Clock_calculus.compute_root_clock (Clock_predef.ck_tuple env_cks) in

373

(*Clocks.new_var true in

374

Clock_calculus.unify_imported_clock (Some call_ck) eq.eq_rhs.expr_clock eq.eq_rhs.expr_loc;

375

Format.eprintf "call %a: %a: %a@," Printers.pp_expr eq.eq_rhs Clocks.print_ck (Clock_predef.ck_tuple env_cks) Clocks.print_ck call_ck;*)

376

(m,

377

(if Stateless.check_node node_f then si else MReset o :: si),

378

Utils.IMap.add o call_f j,

379

d,

380

(if Stateless.check_node node_f

381

then []

382

else reset_instance node args o r call_ck) @

383

(control_on_clock node args call_ck (MStep (var_p, o, vl))) :: s)

384


385

(* special treatment depending on the active backend. For horn backend, x = ite (g,t,e)

386

are preserved. While they are replaced as if g then x = t else x = e in C or Java

387

backends. *)

388

 [x], Expr_ite (c, t, e)

389

when (match !Options.output with  "horn" > true  "C"  "java"  _ > false)

390

>

391

let var_x = get_node_var x node in

392

(m,

393

si,

394

j,

395

d,

396

(control_on_clock node args eq.eq_rhs.expr_clock

397

(MLocalAssign (var_x, translate_expr node args eq.eq_rhs))::s)

398

)

399


400

 [x], _ > (

401

let var_x = get_node_var x node in

402

(m, si, j, d,

403

control_on_clock

404

node

405

args

406

eq.eq_rhs.expr_clock

407

(translate_act node args (var_x, eq.eq_rhs)) :: s

408

)

409

)

410

 _ >

411

begin

412

Format.eprintf "unsupported equation: %a@?" Printers.pp_node_eq eq;

413

assert false

414

end

415


416

let find_eq xl eqs =

417

let rec aux accu eqs =

418

match eqs with

419

 [] >

420

begin

421

Format.eprintf "Looking for variables %a in the following equations@.%a@."

422

(Utils.fprintf_list ~sep:" , " (fun fmt v > Format.fprintf fmt "%s" v)) xl

423

Printers.pp_node_eqs eqs;

424

assert false

425

end

426

 hd::tl >

427

if List.exists (fun x > List.mem x hd.eq_lhs) xl then hd, accu@tl else aux (hd::accu) tl

428

in

429

aux [] eqs

430


431

(* Sort the set of equations of node [nd] according

432

to the computed schedule [sch]

433

*)

434

let sort_equations_from_schedule nd sch =

435

(* Format.eprintf "%s schedule: %a@."

436

nd.node_id

437

(Utils.fprintf_list ~sep:" ; " Scheduling.pp_eq_schedule) sch;*)

438

let split_eqs = Splitting.tuple_split_eq_list (get_node_eqs nd) in

439

let eqs_rev, remainder =

440

List.fold_left

441

(fun (accu, node_eqs_remainder) vl >

442

if List.exists (fun eq > List.exists (fun v > List.mem v eq.eq_lhs) vl) accu

443

then

444

(accu, node_eqs_remainder)

445

else

446

let eq_v, remainder = find_eq vl node_eqs_remainder in

447

eq_v::accu, remainder

448

)

449

([], split_eqs)

450

sch

451

in

452

begin

453

if List.length remainder > 0 then (

454

Format.eprintf "Equations not used are@.%a@.Full equation set is:@.%a@.@?"

455

Printers.pp_node_eqs remainder

456

Printers.pp_node_eqs (get_node_eqs nd);

457

assert false);

458

List.rev eqs_rev

459

end

460


461

let translate_eqs node args eqs =

462

List.fold_right (fun eq args > translate_eq node args eq) eqs args;;

463


464

let translate_decl nd sch =

465

(*Log.report ~level:1 (fun fmt > Printers.pp_node fmt nd);*)

466


467

let sorted_eqs = sort_equations_from_schedule nd sch in

468


469

let init_args = ISet.empty, [], Utils.IMap.empty, List.fold_right (fun l > ISet.add l) nd.node_locals ISet.empty, [] in

470

(* memories, init instructions, node calls, local variables (including memories), step instrs *)

471

let m, init, j, locals, s = translate_eqs nd init_args sorted_eqs in

472

let mmap = Utils.IMap.fold (fun i n res > (i, n)::res) j [] in

473

{

474

mname = nd;

475

mmemory = ISet.elements m;

476

mcalls = mmap;

477

minstances = List.filter (fun (_, (n,_)) > not (Stateless.check_node n)) mmap;

478

minit = init;

479

mstatic = List.filter (fun v > v.var_dec_const) nd.node_inputs;

480

mstep = {

481

step_inputs = nd.node_inputs;

482

step_outputs = nd.node_outputs;

483

step_locals = ISet.elements (ISet.diff locals m);

484

step_checks = List.map (fun d > d.Dimension.dim_loc, translate_expr nd init_args (expr_of_dimension d)) nd.node_checks;

485

step_instrs = (

486

(* special treatment depending on the active backend. For horn backend,

487

common branches are not merged while they are in C or Java

488

backends. *)

489

match !Options.output with

490

 "horn" > s

491

 "C"  "java"  _ > join_guards_list s

492

);

493

step_asserts =

494

let exprl = List.map (fun assert_ > assert_.assert_expr ) nd.node_asserts in

495

List.map (translate_expr nd init_args) exprl

496

;

497

};

498

mspec = nd.node_spec;

499

mannot = nd.node_annot;

500

}

501


502

(** takes the global delcarations and the scheduling associated to each node *)

503

let translate_prog decls node_schs =

504

let nodes = get_nodes decls in

505

List.map

506

(fun decl >

507

let node = node_of_top decl in

508

let sch = (Utils.IMap.find node.node_id node_schs).Scheduling.schedule in

509

translate_decl node sch

510

) nodes

511


512

let get_machine_opt name machines =

513

List.fold_left

514

(fun res m >

515

match res with

516

 Some _ > res

517

 None > if m.mname.node_id = name then Some m else None)

518

None machines

519


520


521

(* Local Variables: *)

522

(* compilecommand:"make C .." *)

523

(* End: *)
