aboutsummaryrefslogtreecommitdiffstats
path: root/scheduling/BTL_SEsimuref.v
blob: 51b562c75823a730be17efa38f03b6aaaadeefe4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
(** Refinement of BTL_SEtheory data-structures
    in order to introduce (and prove correct) a lower-level specification of the simulation test.
*)

Require Import Coqlib Maps Floats.
Require Import AST Integers Values Events Memory Globalenvs Smallstep.
Require Import Op Registers.
Require Import RTL BTL OptionMonad BTL_SEtheory.


Local Open Scope option_monad_scope.

(** * Refinement of data-structures and of the specification of the simulation test *)

Local Hint Resolve OK_PRE OK_SMEM OK_SREG: core.
Local Hint Constructors si_ok: core.

(* NB: refinement of (symbolic) internal state *)
Record ristate := 
  { 
    (** [ris_smem] represents the current smem symbolic evaluations.
        (we also recover the history of smem in ris_smem)  *)
    ris_smem:> smem;
    (** For the values in registers:
        1) we store a list of sval evaluations
        2) we encode the symbolic regset by a PTree + a boolean indicating the default sval
        See [ris_sreg_get] below.
     *)
    ris_input_init: bool;
    ok_rsval: list sval;
    ris_sreg:> PTree.t sval
  }.

Definition ris_sreg_get (ris: ristate) r: sval :=
   match PTree.get r (ris_sreg ris) with
   | None => if ris_input_init ris then fSinput r else fSundef
   | Some sv => sv
   end.

Coercion ris_sreg_get: ristate >-> Funclass.

Definition ris_sreg_set (ris: ristate) (sreg: PTree.t sval): ristate :=
  {| ris_smem := ris_smem ris;
     ris_input_init := ris_input_init ris;
     ok_rsval := ok_rsval ris;
     ris_sreg := sreg |}.

Lemma ris_sreg_set_access (ris: ristate) (sreg: PTree.t sval) r smem rsval:
  {| ris_smem := smem;
     ris_input_init := ris_input_init ris;
     ok_rsval := rsval;
     ris_sreg := sreg |} r =
  ris_sreg_set ris sreg r.
Proof.
  unfold ris_sreg_set, ris_sreg_get; simpl.
  reflexivity.
Qed.

Record ris_ok ctx (ris: ristate) : Prop := {
  OK_RMEM: (eval_smem ctx (ris_smem ris)) <> None;
  OK_RREG: forall sv, List.In sv (ok_rsval ris) -> eval_sval ctx sv <> None
}.
Local Hint Resolve OK_RMEM OK_RREG: core.
Local Hint Constructors ris_ok: core.

(**
   NOTE that this refinement relation *cannot* be decomposed into a abstraction function of type 
   ristate -> sistate & an equivalence relation on istate.

   Indeed, any [sis] satisfies [forall ctx r, si_ok ctx sis -> eval_sval ctx (sis r) <> None].
   whereas this is generally not true for [ris] that [forall ctx r, ris_ok ctx ris -> eval_sval ctx (ris r) <> None], 
   except when, precisely, [ris_refines ris sis].

   An alternative design enabling to define ris_refines as the composition of an equivalence on sistate 
   and a abstraction function would consist in constraining sistate with an additional [wf] field:

   Record sistate := 
    { si_pre: iblock_exec_context -> Prop; 
      si_sreg:> reg -> sval;
      si_smem: smem;
      si_wf: forall ctx, si_pre ctx -> si_smem <> None /\ forall r, si_sreg r <> None 
   }.

  Such a constraint should also appear in [ristate]. This is not clear whether this alternative design 
  would be really simpler.

*)
Record ris_refines ctx (ris: ristate) (sis: sistate): Prop := {
  OK_EQUIV: si_ok ctx sis <-> ris_ok ctx ris;
  MEM_EQ: ris_ok ctx ris ->  eval_smem ctx ris.(ris_smem) = eval_smem ctx sis.(si_smem);
  REG_EQ: ris_ok ctx ris -> forall r, eval_sval ctx (ris r) = eval_sval ctx (sis r)
}.
Local Hint Resolve OK_EQUIV MEM_EQ REG_EQ: core.
Local Hint Constructors ris_refines: core.

Record ris_simu ris1 ris2: Prop := {
  SIMU_FAILS: forall sv, List.In sv ris2.(ok_rsval) -> List.In sv ris1.(ok_rsval);
  SIMU_MEM: ris1.(ris_smem) = ris2.(ris_smem);
  SIMU_REG: forall r, ris1 r = ris2 r
}.
Local Hint Resolve SIMU_FAILS SIMU_MEM SIMU_REG: core.
Local Hint Constructors ris_simu: core.
Local Hint Resolve sge_match: core.

Lemma ris_simu_ok_preserv f1 f2 ris1 ris2 (ctx:simu_proof_context f1 f2):
  ris_simu ris1 ris2 -> ris_ok (bctx1 ctx) ris1 -> ris_ok (bctx2 ctx) ris2.
Proof.
  intros SIMU OK; econstructor; eauto.
  - erewrite <- SIMU_MEM; eauto.
    erewrite <- smem_eval_preserved; eauto.
  - intros; erewrite <- eval_sval_preserved; eauto.
Qed.

Lemma ris_simu_correct f1 f2 ris1 ris2 (ctx:simu_proof_context f1 f2) sis1 sis2: 
  ris_simu ris1 ris2 ->
  ris_refines (bctx1 ctx) ris1 sis1 ->
  ris_refines (bctx2 ctx) ris2 sis2 ->
  sistate_simu ctx sis1 sis2.
Proof.
  intros RIS REF1 REF2 rs m SEM.
  exploit sem_si_ok; eauto.
  erewrite OK_EQUIV; eauto.
  intros ROK1.
  exploit ris_simu_ok_preserv; eauto.
  intros ROK2. generalize ROK2; erewrite <- OK_EQUIV; eauto.
  intros SOK2.
  destruct SEM as (PRE & SMEM & SREG).
  unfold sem_sistate; intuition eauto.
  + erewrite <- MEM_EQ, <- SIMU_MEM; eauto.
    erewrite <- smem_eval_preserved; eauto.
    erewrite MEM_EQ; eauto.
  + erewrite <- REG_EQ, <- SIMU_REG; eauto.
    erewrite <- eval_sval_preserved; eauto.
    erewrite REG_EQ; eauto.
Qed.

Inductive optrsv_refines ctx: (option sval) -> (option sval) -> Prop :=
  | RefSome rsv sv
     (REF:eval_sval ctx rsv = eval_sval ctx sv)
     :optrsv_refines ctx (Some rsv) (Some sv)
  | RefNone: optrsv_refines ctx None None
  .

Inductive rsvident_refines ctx: (sval + ident) -> (sval + ident) -> Prop :=
  | RefLeft rsv sv
     (REF:eval_sval ctx rsv = eval_sval ctx sv)
     :rsvident_refines ctx (inl rsv) (inl sv)
  | RefRight id1 id2
     (IDSIMU: id1 = id2)
     :rsvident_refines ctx (inr id1) (inr id2)
  .

Definition bargs_refines ctx (rargs: list (builtin_arg sval)) (args: list (builtin_arg sval)): Prop :=
  eval_list_builtin_sval ctx rargs = eval_list_builtin_sval ctx args.

Inductive rfv_refines ctx: sfval -> sfval -> Prop :=
  | RefGoto pc: rfv_refines ctx (Sgoto pc) (Sgoto pc)
  | RefCall sig rvos ros rargs args r pc
      (SV:rsvident_refines ctx rvos ros)
      (LIST:eval_list_sval ctx rargs = eval_list_sval ctx args)
      :rfv_refines ctx (Scall sig rvos rargs r pc) (Scall sig ros args r pc)
  | RefTailcall sig rvos ros rargs args
      (SV:rsvident_refines ctx rvos ros)
      (LIST:eval_list_sval ctx rargs = eval_list_sval ctx args)
      :rfv_refines ctx (Stailcall sig rvos rargs) (Stailcall sig ros args)
  | RefBuiltin ef lbra lba br pc
      (BARGS: bargs_refines ctx lbra lba)
      :rfv_refines ctx (Sbuiltin ef lbra br pc) (Sbuiltin ef lba br pc)
  | RefJumptable rsv sv lpc
      (VAL: eval_sval ctx rsv = eval_sval ctx sv)
      :rfv_refines ctx (Sjumptable rsv lpc) (Sjumptable sv lpc)
  | RefReturn orsv osv
      (OPT:optrsv_refines ctx orsv osv)
      :rfv_refines ctx (Sreturn orsv) (Sreturn osv)
.

Definition rfv_simu (rfv1 rfv2: sfval): Prop := rfv1 = rfv2.

Local Hint Resolve eval_sval_preserved list_sval_eval_preserved smem_eval_preserved eval_list_builtin_sval_preserved: core.

Lemma rvf_simu_correct f1 f2 rfv1 rfv2 (ctx: simu_proof_context f1 f2) sfv1 sfv2: 
  rfv_simu rfv1 rfv2 ->
  rfv_refines (bctx1 ctx) rfv1 sfv1 ->
  rfv_refines (bctx2 ctx) rfv2 sfv2 ->
  sfv_simu ctx sfv1 sfv2.
Proof.
  unfold rfv_simu; intros X REF1 REF2. subst.
  unfold bctx2; destruct REF1; inv REF2; simpl; econstructor; eauto.
  - (* call svid *)
    inv SV; inv SV0; econstructor; eauto.
    rewrite <- REF, <- REF0; eauto.
  - (* call args *)
    rewrite <- LIST, <- LIST0; eauto.
  - (* taillcall svid *)
    inv SV; inv SV0; econstructor; eauto.
    rewrite <- REF, <- REF0; eauto.
  - (* tailcall args *)
    rewrite <- LIST, <- LIST0; eauto.
  - (* builtin args *)
    unfold bargs_refines, bargs_simu in *.
    rewrite <- BARGS, <- BARGS0; eauto.
  - rewrite <- VAL, <- VAL0; eauto.
  - (* return *)
    inv OPT; inv OPT0; econstructor; eauto.
    rewrite <- REF, <- REF0; eauto.
Qed.

(* refinement of (symbolic) state *)
Inductive rstate :=
  | Rfinal (ris: ristate) (rfv: sfval)
  | Rcond (cond: condition) (rargs: list_sval) (rifso rifnot: rstate)
  | Rabort
  .

Record routcome := rout {
  _ris: ristate;
  _rfv: sfval;
}.

Fixpoint get_routcome ctx (rst:rstate): option routcome :=
  match rst with
  | Rfinal ris rfv => Some (rout ris rfv)
  | Rcond cond args ifso ifnot =>
     SOME b <- eval_scondition ctx cond args IN
     get_routcome ctx (if b then ifso else ifnot)
  | Rabort => None
  end.

Inductive rst_simu: rstate -> rstate -> Prop :=
  | Rfinal_simu ris1 ris2 rfv1 rfv2
      (RIS: ris_simu ris1 ris2)
      (RFV: rfv_simu rfv1 rfv2)
      : rst_simu (Rfinal ris1 rfv1) (Rfinal ris2 rfv2)
  | Rcond_simu cond rargs rifso1 rifnot1 rifso2 rifnot2
      (IFSO: rst_simu rifso1 rifso2)
      (IFNOT: rst_simu rifnot1 rifnot2)
      : rst_simu (Rcond cond rargs rifso1 rifnot1) (Rcond cond rargs rifso2 rifnot2)
  | Rabort_simu: rst_simu Rabort Rabort
(* TODO: extension à voir dans un second temps !
  | Rcond_skip cond rargs rifso1 rifnot1 rst:
      rst_simu rifso1 rst ->
      rst_simu rifnot1 rst ->
      rst_simu (Rcond cond rargs rifso1 rifnot1) rst
*)
  .

Lemma rst_simu_lroutcome rst1 rst2:
   rst_simu rst1 rst2 ->
   forall f1 f2 (ctx: simu_proof_context f1 f2) ris1 rfv1,
   get_routcome (bctx1 ctx) rst1 = Some (rout ris1 rfv1) ->
   exists ris2 rfv2, get_routcome (bctx2 ctx) rst2 = Some (rout ris2 rfv2) /\ ris_simu ris1 ris2 /\ rfv_simu rfv1 rfv2.
Proof.
  induction 1; simpl; intros f1 f2 ctx lris1 lrfv1 ROUT; try_simplify_someHyps.
  erewrite <- eval_scondition_preserved.
  autodestruct.
  destruct b; simpl; auto.
Qed.

Inductive rst_refines ctx: rstate -> sstate -> Prop :=
  | Reffinal ris sis rfv sfv
      (RIS: ris_refines ctx ris sis)
      (RFV: ris_ok ctx ris -> rfv_refines ctx rfv sfv)
      : rst_refines ctx (Rfinal ris rfv) (Sfinal sis sfv)
  | Refcond rcond cond rargs args rifso rifnot ifso ifnot
      (RCOND: eval_scondition ctx rcond rargs = eval_scondition ctx cond args)
      (REFso: eval_scondition ctx rcond rargs = Some true -> rst_refines ctx rifso ifso)
      (REFnot: eval_scondition ctx rcond rargs = Some false -> rst_refines ctx rifnot ifnot)
      : rst_refines ctx (Rcond rcond rargs rifso rifnot) (Scond cond args ifso ifnot)
  | Refabort
      : rst_refines ctx Rabort Sabort
  .

Lemma rst_refines_outcome_up ctx rst st:
   rst_refines ctx rst st ->
   forall ris rfv,
   get_routcome ctx rst = Some (rout ris rfv) ->
   exists sis sfv, get_soutcome ctx st = Some (sout sis sfv) /\ ris_refines ctx ris sis /\ (ris_ok ctx ris -> rfv_refines ctx rfv sfv).
Proof.
  induction 1; simpl; intros lris lrfv ROUT; try_simplify_someHyps.
  rewrite RCOND.
  autodestruct.
  destruct b; simpl; auto.
Qed.

Lemma rst_refines_outcome_okpreserv ctx rst st:
   rst_refines ctx rst st ->
   forall sis sfv,
   get_soutcome ctx st = Some (sout sis sfv) ->
   exists ris rfv, get_routcome ctx rst = Some (rout ris rfv) /\ ris_refines ctx ris sis /\ (ris_ok ctx ris -> rfv_refines ctx rfv sfv).
Proof.
  induction 1; simpl; intros lris lrfv ROUT; try_simplify_someHyps.
  rewrite RCOND.
  autodestruct.
  destruct b; simpl; auto.
Qed.

Local Hint Resolve ris_simu_correct rvf_simu_correct: core.

Lemma rst_simu_correct f1 f2 (ctx: simu_proof_context f1 f2) rst1 rst2 st1 st2
   (SIMU: rst_simu rst1 rst2) 
   (REF1: forall sis sfv, get_soutcome (bctx1 ctx) st1 = Some (sout sis sfv) -> si_ok (bctx1 ctx) sis -> rst_refines (bctx1 ctx) rst1 st1)
   (REF2: forall ris rfv, get_routcome (bctx2 ctx) rst2 = Some (rout ris rfv) -> ris_ok (bctx2 ctx) ris -> rst_refines (bctx2 ctx) rst2 st2)
   :sstate_simu ctx st1 st2.
Proof.
  intros sis1 sfv1 SOUT OK1.
  exploit REF1; eauto.
  clear REF1; intros REF1.
  exploit rst_refines_outcome_okpreserv; eauto. clear REF1 SOUT.
  intros (ris1 & rfv1 & ROUT1 & REFI1 & REFF1).
  rewrite OK_EQUIV in OK1; eauto. 
  exploit REFF1; eauto. clear REFF1; intros REFF1.
  exploit rst_simu_lroutcome; eauto.
  intros (ris2 & rfv2 & ROUT2 & SIMUI & SIMUF). clear ROUT1.
  exploit ris_simu_ok_preserv; eauto.
  clear OK1. intros OK2.
  exploit REF2; eauto. clear REF2; intros REF2.
  exploit rst_refines_outcome_up; eauto.
  intros (sis2 & sfv2 & SOUT & REFI2 & REFF2).
  do 2 eexists; split; eauto.
Qed.


(** * Properties of the (abstract) operators involved in symbolic execution *)

Lemma ok_set_mem ctx sm sis:
  si_ok ctx (set_smem sm sis)
  <-> (si_ok ctx sis /\ eval_smem ctx sm <> None).
Proof.
  split; destruct 1; econstructor; simpl in *; eauto.
  intuition eauto.
Qed.

Lemma ok_set_sreg ctx r sv sis:
  si_ok ctx (set_sreg r sv sis)
  <-> (si_ok ctx sis /\ eval_sval ctx sv <> None).
Proof.
  unfold set_sreg; split.
  + intros [(SVAL & PRE) SMEM SREG]; simpl in *; split.
    - econstructor; eauto.
      intros r0; generalize (SREG r0); destruct (Pos.eq_dec r r0); try congruence.
    - generalize (SREG r); destruct (Pos.eq_dec r r); try congruence.
  + intros ([PRE SMEM SREG] & SVAL).
    econstructor; simpl; eauto.
    intros r0;  destruct (Pos.eq_dec r r0); try congruence.
Qed.

Lemma si_ok_op_okpreserv ctx op args dest sis: si_ok ctx (sexec_op op args dest sis) -> si_ok ctx sis.
Proof.
  unfold sexec_op. rewrite ok_set_sreg. intuition.
Qed.

Lemma si_ok_load_okpreserv ctx chunk addr args dest sis trap: si_ok ctx (sexec_load trap chunk addr args dest sis) -> si_ok ctx sis.
Proof.
  unfold sexec_load. rewrite ok_set_sreg. intuition.
Qed.

Lemma si_ok_store_okpreserv ctx chunk addr args src sis: si_ok ctx (sexec_store chunk addr args src sis) -> si_ok ctx sis.
Proof.
  unfold sexec_store. rewrite ok_set_mem. intuition.
Qed.

Lemma si_ok_tr_okpreserv ctx fi sis: si_ok ctx (tr_sis (cf ctx) fi sis) -> si_ok ctx sis.
Proof.
  unfold tr_sis. intros OK; inv OK. simpl in *. intuition.
Qed.

(* These lemmas are very bad for eauto: we put them into a dedicated basis. *)
Local Hint Resolve si_ok_tr_okpreserv si_ok_op_okpreserv si_ok_load_okpreserv si_ok_store_okpreserv: sis_ok.

Lemma sexec_rec_okpreserv ctx ib: 
  forall k
  (CONT: forall sis lsis sfv, get_soutcome ctx (k sis) = Some (sout lsis sfv) ->  si_ok ctx lsis -> si_ok ctx sis)
  sis lsis sfv
  (SOUT: get_soutcome ctx (sexec_rec (cf ctx) ib sis k) = Some (sout lsis sfv))
  (OK: si_ok ctx lsis)
  ,si_ok ctx sis.
Proof.
  induction ib; simpl; try (autodestruct; simpl).
  1-6: try_simplify_someHyps; eauto with sis_ok.
  - intros. eapply IHib1. 2-3: eauto.
    eapply IHib2; eauto.
  - intros k CONT sis lsis sfv.
    do 2 autodestruct; eauto.
Qed.

(* an alternative tr_sis *)

Definition transfer_sis (inputs: list reg) (sis:sistate): sistate :=
   {| si_pre := fun ctx => (sis.(si_pre) ctx /\ forall r, eval_sval ctx (sis.(si_sreg) r) <> None);
      si_sreg := transfer_sreg inputs sis;
      si_smem := sis.(si_smem) |}.

Lemma ok_transfer_sis ctx inputs sis:
  si_ok ctx (transfer_sis inputs sis)
  <-> (si_ok ctx sis).
Proof.
  unfold transfer_sis. induction inputs as [|r l]; simpl.
  + split; destruct 1; econstructor; simpl in *; intuition eauto. congruence.
  + split.
    * destruct 1; econstructor; simpl in *; intuition eauto.
    * intros X; generalize X. rewrite <- IHl in X; clear IHl.
      intros [PRE SMEM SREG].
      econstructor; simpl; eauto.
      intros r0;  destruct (Pos.eq_dec r r0); try congruence.
      intros H; eapply OK_SREG; eauto.
Qed.

Definition alt_tr_sis := poly_tr (fun f tbl or => transfer_sis (Regset.elements (pre_inputs f tbl or))).

Lemma tr_sis_alt_def f fi sis:
  alt_tr_sis f fi sis = tr_sis f fi sis.
Proof.
  unfold tr_sis, str_inputs. destruct fi; simpl; auto.
Qed.


(** * Refinement of the symbolic execution (e.g. refinement of [sexec] into [rexec]).

TODO: Est-ce qu'on garde cette vision purement fonctionnelle de l'implementation ?
=> ça pourrait être pratique quand on va compliquer encore le vérificateur !

Du coup, on introduirait une version avec hash-consing qui serait en correspondance 
pour une relation d'equivalence sur les ristate ?

Attention toutefois, il est possible que certaines parties de l'execution soient pénibles à formuler 
en programmation fonctionnelle pure (exemple: usage de l'égalité de pointeur comme test d'égalité rapide!)


*)

Local Hint Constructors rfv_refines optrsv_refines rsvident_refines rsvident_refines: core.

Lemma eval_list_sval_refpreserv ctx args ris sis:
  ris_refines ctx ris sis ->
  ris_ok ctx ris ->
  eval_list_sval ctx (list_sval_inj (map ris args)) =
  eval_list_sval ctx (list_sval_inj (map (si_sreg sis) args)).
Proof.
  intros REF OK.
  induction args; simpl; eauto.
  intros; erewrite REG_EQ, IHargs; eauto.
Qed.

Local Hint Resolve eval_list_sval_refpreserv: core.

Lemma eval_builtin_sval_refpreserv ctx arg ris sis:
  ris_refines ctx ris sis ->
  ris_ok ctx ris ->
  eval_builtin_sval ctx (builtin_arg_map ris arg) = eval_builtin_sval ctx (builtin_arg_map sis arg).
Proof.
  intros REF OK; induction arg; simpl; eauto.
  + erewrite REG_EQ; eauto.
  + erewrite IHarg1, IHarg2; eauto.
  + erewrite IHarg1, IHarg2; eauto.
Qed.

Lemma bargs_refpreserv ctx args ris sis:
  ris_refines ctx ris sis ->
  ris_ok ctx ris ->
  bargs_refines ctx (map (builtin_arg_map ris) args) (map (builtin_arg_map sis) args).
Proof.
  unfold bargs_refines. intros REF OK.
  induction args; simpl; eauto.
  erewrite eval_builtin_sval_refpreserv, IHargs; eauto.
Qed.

Local Hint Resolve bargs_refpreserv: core.

Lemma exec_final_refpreserv ctx i ris sis:
  ris_refines ctx ris sis ->
  ris_ok ctx ris ->
  rfv_refines ctx (sexec_final_sfv i ris) (sexec_final_sfv i sis).
Proof.
  destruct i; simpl; unfold sum_left_map; try autodestruct; eauto.
Qed.

Definition ris_init: ristate := {| ris_smem:= fSinit; ris_input_init:=true; ok_rsval := nil; ris_sreg := PTree.empty _ |}.

Lemma ris_init_correct ctx:
  ris_refines ctx ris_init sis_init.
Proof.
  unfold ris_init, sis_init; econstructor; simpl in *; eauto.
  split; destruct 1; econstructor; simpl in *; eauto.
    congruence.
Qed.

Definition rset_smem rm (ris:ristate): ristate :=
  {| ris_smem := rm;
     ris_input_init := ris.(ris_input_init);
     ok_rsval := ris.(ok_rsval);
     ris_sreg:= ris.(ris_sreg)
  |}.

Lemma ok_rset_mem ctx rm (ris: ristate):
  (eval_smem ctx ris.(ris_smem) = None -> eval_smem ctx rm = None) ->
  ris_ok ctx (rset_smem rm ris)
  <-> (ris_ok ctx ris /\ eval_smem ctx rm <> None).
Proof.
   split; destruct 1; econstructor; simpl in *; eauto.
Qed.

Lemma rset_mem_correct ctx rm sm ris sis:
  (eval_smem ctx ris.(ris_smem) = None -> eval_smem ctx rm = None) ->
  ris_refines ctx ris sis ->
  (ris_ok ctx ris -> eval_smem ctx rm = eval_smem ctx sm) ->
  ris_refines ctx (rset_smem rm ris) (set_smem sm sis).
Proof.
  destruct 2; intros.
  econstructor; eauto.
  + rewrite ok_set_mem, ok_rset_mem; intuition congruence.
  + rewrite ok_rset_mem; intuition eauto.
  + rewrite ok_rset_mem; intuition eauto.
Qed.

Definition rexec_store chunk addr args src ris: ristate :=
   let args := list_sval_inj (List.map (ris_sreg_get ris) args) in
   let src := ris_sreg_get ris src in
   let rm := fSstore ris.(ris_smem) chunk addr args src in
   rset_smem rm ris.

Lemma rexec_store_correct ctx chunk addr args src ris sis:
  ris_refines ctx ris sis ->
  ris_refines ctx (rexec_store chunk addr args src ris) (sexec_store chunk addr args src sis).
Proof.
  intros REF; eapply rset_mem_correct; simpl; eauto.
  + intros X; rewrite X. repeat autodestruct; eauto.
  + intros OK; erewrite eval_list_sval_refpreserv, MEM_EQ, REG_EQ; eauto.
Qed.

(* TODO: reintroduire le "root_apply" ? *)

Definition rset_sreg r rsv (ris:ristate): ristate :=
  {| ris_smem := ris.(ris_smem);
     ris_input_init := ris.(ris_input_init);
     ok_rsval := rsv::ris.(ok_rsval); (* TODO: A CHANGER ? *)
     ris_sreg:= PTree.set r rsv ris.(ris_sreg) (* TODO: A CHANGER *)
  |}.

Lemma ok_rset_sreg ctx r rsv ris:
  ris_ok ctx (rset_sreg r rsv ris)
  <-> (ris_ok ctx ris /\ eval_sval ctx rsv <> None).
Proof.
   split; destruct 1; econstructor; simpl in *; eauto.
   intuition subst; eauto.
   exploit OK_RREG; eauto.
Qed.

Lemma rset_reg_correct ctx r rsv sv ris sis:
  ris_refines ctx ris sis ->
  (ris_ok ctx ris -> eval_sval ctx rsv = eval_sval ctx sv) ->
  ris_refines ctx (rset_sreg r rsv ris) (set_sreg r sv sis).
Proof.
  destruct 1; intros.
  econstructor; eauto.
  + rewrite ok_set_sreg, ok_rset_sreg; intuition congruence.
  + rewrite ok_rset_sreg; intuition eauto.
  + rewrite ok_rset_sreg. intros; unfold rset_sreg, set_sreg, ris_sreg_get; simpl. intuition eauto.
    destruct (Pos.eq_dec _ _).
    * subst; rewrite PTree.gss; eauto.
    * rewrite PTree.gso; eauto.
Qed.

Definition rexec_op op args dst (ris:ristate): ristate :=
   let args := list_sval_inj (List.map ris args) in
   rset_sreg dst (fSop op args) ris.

Lemma rexec_op_correct ctx op args dst ris sis:
  ris_refines ctx ris sis ->
  ris_refines ctx (rexec_op op args dst ris) (sexec_op op args dst sis).
Proof.
  intros REF; eapply rset_reg_correct; simpl; eauto.
  intros OK; erewrite eval_list_sval_refpreserv; eauto.
Qed.

Definition rexec_load trap chunk addr args dst (ris:ristate): ristate :=
   let args := list_sval_inj (List.map ris args) in
   rset_sreg dst (fSload ris.(ris_smem) trap chunk addr args) ris.

Lemma rexec_load_correct ctx trap chunk addr args dst ris sis:
  ris_refines ctx ris sis ->
  ris_refines ctx (rexec_load trap chunk addr args dst ris) (sexec_load trap chunk addr args dst sis).
Proof.
  intros REF; eapply rset_reg_correct; simpl; eauto.
  intros OK; erewrite eval_list_sval_refpreserv, MEM_EQ; eauto.
Qed.

Lemma eval_scondition_refpreserv ctx cond args ris sis:
  ris_refines ctx ris sis ->
  ris_ok ctx ris ->
  eval_scondition ctx cond (list_sval_inj (map ris args)) = eval_scondition ctx cond (list_sval_inj (map sis args)).
Proof.
  intros; unfold eval_scondition.
  erewrite eval_list_sval_refpreserv; eauto.
Qed.


(* transfer *)

Definition rseto_sreg r rsv (ris:ristate): ristate :=
  {| ris_smem := ris.(ris_smem);
     ris_input_init := ris.(ris_input_init);
     ok_rsval := ris.(ok_rsval);
     ris_sreg:= PTree.set r rsv ris.(ris_sreg) (* TODO: A CHANGER *)
  |}.

Lemma ok_rseto_sreg ctx r rsv ris:
  ris_ok ctx (rseto_sreg r rsv ris)
  <-> (ris_ok ctx ris).
Proof.
   split; destruct 1; econstructor; simpl in *; eauto.
Qed.

Lemma rseto_reg_correct ctx r rsv sv ris sis:
  ris_refines ctx ris sis ->
  (ris_ok ctx ris -> eval_sval ctx rsv <> None) ->
  (ris_ok ctx ris -> eval_sval ctx rsv = eval_sval ctx sv) ->
  ris_refines ctx (rseto_sreg r rsv ris) (set_sreg r sv sis).
Proof.
  destruct 1; intros.
  econstructor; eauto.
  + rewrite ok_set_sreg, ok_rseto_sreg; intuition congruence.
  + rewrite ok_rseto_sreg; intuition eauto.
  + rewrite ok_rseto_sreg. intros; unfold rseto_sreg, set_sreg, ris_sreg_get; simpl. intuition eauto.
    destruct (Pos.eq_dec _ _).
    * subst; rewrite PTree.gss; eauto.
    * rewrite PTree.gso; eauto.
Qed.

Fixpoint transfer_ris (inputs: list reg) (ris:ristate): ristate :=
  match inputs with
  | nil =>   {| ris_smem := ris.(ris_smem);
                ris_input_init := false;
                ok_rsval := ris.(ok_rsval);
                ris_sreg:= PTree.empty _
             |}
  | r::l => rseto_sreg r (ris_sreg_get ris r) (transfer_ris l ris)
  end.

Lemma ok_transfer_ris ctx inputs ris:
  ris_ok ctx (transfer_ris inputs ris)
  <-> (ris_ok ctx ris).
Proof.
  induction inputs as [|r l]; simpl.
  + split; destruct 1; econstructor; simpl in *; intuition eauto.
  + rewrite ok_rseto_sreg. auto.
Qed.

Lemma transfer_ris_correct ctx inputs ris sis:
  ris_refines ctx ris sis ->
  ris_refines ctx (transfer_ris inputs ris) (transfer_sis inputs sis).
Proof.
  destruct 1; intros.
  induction inputs as [|r l].
  + econstructor; eauto.
    * erewrite ok_transfer_sis, ok_transfer_ris; eauto.
    * erewrite ok_transfer_ris; eauto.
  + econstructor; eauto.
    * erewrite ok_transfer_sis, ok_transfer_ris; eauto.
    * erewrite ok_transfer_ris; simpl.
      intros; erewrite MEM_EQ. 2: eauto.
      - unfold transfer_sis; simpl; eauto.
      - rewrite ok_transfer_ris; simpl; eauto.
    * erewrite ok_transfer_ris; simpl.
      intros H r0.
      erewrite REG_EQ. 2: eapply rseto_reg_correct; eauto.
      - unfold set_sreg; simpl; auto.
        destruct (Pos.eq_dec _ _); simpl; auto.
      - intros. rewrite REG_EQ0; auto. apply OK_SREG; tauto.
      - rewrite ok_rseto_sreg, ok_transfer_ris. auto.
Qed.

Definition tr_ris := poly_tr (fun f tbl or => transfer_ris (Regset.elements (pre_inputs f tbl or))).

Local Hint Resolve transfer_ris_correct ok_transfer_ris: core.
Local Opaque transfer_ris.

Lemma ok_tr_ris ctx fi ris:
  ris_ok ctx (tr_ris (cf ctx) fi ris)
  <-> (ris_ok ctx ris).
Proof.
   destruct fi; simpl; eauto.
Qed.

Lemma ris_ok_tr_okpreserv ctx fi ris: ris_ok ctx (tr_ris (cf ctx) fi ris) -> ris_ok ctx ris.
Proof.
  rewrite ok_tr_ris; auto.
Qed.

Lemma tr_ris_correct ctx fi ris sis:
  ris_refines ctx ris sis ->
  ris_refines ctx (tr_ris (cf ctx) fi ris) (tr_sis (cf ctx) fi sis).
Proof.
  intros REF. rewrite <- tr_sis_alt_def.
  destruct fi; simpl; eauto.
Qed.

(** RAFFINEMENT EXEC SYMBOLIQUE **)

Fixpoint rexec_rec f ib ris (k: ristate -> rstate): rstate := 
  match ib with
  | BF fin _ => Rfinal (tr_ris f fin ris) (sexec_final_sfv fin ris)
  (* basic instructions *)
  | Bnop _ => k ris
  | Bop op args res _ => k (rexec_op op args res ris)
  | Bload trap chunk addr args dst _ => k (rexec_load trap chunk addr args dst ris)
  | Bstore chunk addr args src _ => k (rexec_store chunk addr args src ris)
 (* composed instructions *)
  | Bseq ib1 ib2 =>
      rexec_rec f ib1 ris (fun ris2 => rexec_rec f ib2 ris2 k)
  | Bcond cond args ifso ifnot _ =>
      let args := list_sval_inj (List.map ris args) in
      let ifso := rexec_rec f ifso ris k in
      let ifnot := rexec_rec f ifnot ris k in
      Rcond cond args ifso ifnot
  end
  .

Definition rexec f ib := rexec_rec f ib ris_init (fun _ => Rabort).


Local Hint Resolve ris_init_correct exec_final_refpreserv tr_ris_correct ris_ok_tr_okpreserv
  rexec_op_correct rexec_load_correct rexec_store_correct: core.

Local Hint Constructors rst_refines: core.

Lemma rexec_rec_correct1 ctx ib: 
  forall rk k
  (CONTh: forall sis lsis sfv, get_soutcome ctx (k sis) = Some (sout lsis sfv) ->  si_ok ctx lsis -> si_ok ctx sis)
  (CONT: forall ris sis lsis sfv st, ris_refines ctx ris sis -> k sis = st -> get_soutcome ctx (k sis) = Some (sout lsis sfv) -> si_ok ctx lsis -> rst_refines ctx (rk ris) (k sis))
  ris sis lsis sfv st
  (REF: ris_refines ctx ris sis)
  (EXEC: sexec_rec (cf ctx) ib sis k = st)
  (SOUT: get_soutcome ctx st = Some (sout lsis sfv))
  (OK: si_ok ctx lsis)
  , rst_refines ctx (rexec_rec (cf ctx) ib ris rk) st.
Proof.
  induction ib; simpl; try (intros; subst; eauto; fail).
  - (* seq *)
    intros; subst.
    eapply IHib1. 3-6: eauto.
    + simpl. eapply sexec_rec_okpreserv; eauto.
    + intros; subst. eapply IHib2; eauto.
  - (* cond *)
    intros rk k CONTh CONT ris sis lsis sfv st REF EXEC OUT OK. subst.
    assert (rOK: ris_ok ctx ris). {
      erewrite <- OK_EQUIV. 2: eauto.
      eapply sexec_rec_okpreserv with (ib:=(Bcond cond args ib1 ib2 iinfo)); simpl; eauto.
    }
    generalize OUT; clear OUT; simpl.
    autodestruct.
    intros COND; generalize COND.
    erewrite <- eval_scondition_refpreserv; eauto.
    econstructor; try_simplify_someHyps.
Qed.

Lemma rexec_correct1 ctx ib sis sfv:
  get_soutcome ctx (sexec (cf ctx) ib) = Some (sout sis sfv) ->
  (si_ok ctx sis) ->
  rst_refines ctx (rexec (cf ctx) ib) (sexec (cf ctx) ib).
Proof.
  unfold sexec; intros; eapply rexec_rec_correct1; eauto; simpl; congruence.
Qed.


(** COPIER-COLLER ... Y a-t-il moyen de l'eviter ? **)

Lemma ris_ok_op_okpreserv ctx op args dest ris: ris_ok ctx (rexec_op op args dest ris) -> ris_ok ctx ris.
Proof.
  unfold rexec_op. rewrite ok_rset_sreg. intuition.
Qed.

Lemma ris_ok_load_okpreserv ctx chunk addr args dest ris trap: ris_ok ctx (rexec_load trap chunk addr args dest ris) -> ris_ok ctx ris.
Proof.
  unfold rexec_load. rewrite ok_rset_sreg. intuition.
Qed.

Lemma ris_ok_store_okpreserv ctx chunk addr args src ris: ris_ok ctx (rexec_store chunk addr args src ris) -> ris_ok ctx ris.
Proof.
  unfold rexec_store. rewrite ok_rset_mem; simpl. 
  + intuition.
  + intros X; rewrite X; simpl.
    repeat autodestruct.
Qed.

(* These lemmas are very bad for eauto: we put them into a dedicated basis. *)
Local Hint Resolve ris_ok_store_okpreserv ris_ok_op_okpreserv ris_ok_load_okpreserv: ris_ok.

Lemma rexec_rec_okpreserv ctx ib: 
  forall k
  (CONT: forall ris lris rfv, get_routcome ctx (k ris) = Some (rout lris rfv) ->  ris_ok ctx lris -> ris_ok ctx ris)
  ris lris rfv
  (ROUT: get_routcome ctx (rexec_rec (cf ctx) ib ris k) = Some (rout lris rfv))
  (OK: ris_ok ctx lris)
  ,ris_ok ctx ris.
Proof.
  induction ib; simpl; try (autodestruct; simpl).
  1-6: try_simplify_someHyps; eauto with ris_ok.
  - intros. eapply IHib1. 2-3: eauto.
    eapply IHib2; eauto.
  - intros k CONT sis lsis sfv.
    do 2 autodestruct; eauto.
Qed.

Lemma rexec_rec_correct2 ctx ib: 
  forall rk k
  (CONTh: forall ris lris rfv, get_routcome ctx (rk ris) = Some (rout lris rfv) ->  ris_ok ctx lris -> ris_ok ctx ris)
  (CONT: forall ris sis lris rfv st, ris_refines ctx ris sis -> rk ris = st -> get_routcome ctx (rk ris) = Some (rout lris rfv) -> ris_ok ctx lris -> rst_refines ctx (rk ris) (k sis))
  ris sis lris rfv st
  (REF: ris_refines ctx ris sis)
  (EXEC: rexec_rec (cf ctx) ib ris rk = st)
  (SOUT: get_routcome ctx st = Some (rout lris rfv))
  (OK: ris_ok ctx lris)
  , rst_refines ctx st (sexec_rec (cf ctx) ib sis k).
Proof.
  induction ib; simpl; try (intros; subst; eauto; fail).
  - (* seq *)
    intros; subst.
    eapply IHib1. 3-6: eauto.
    + simpl. eapply rexec_rec_okpreserv; eauto.
    + intros; subst. eapply IHib2; eauto.
  - (* cond *)
    intros rk k CONTh CONT ris sis lsis sfv st REF EXEC OUT OK. subst.
    assert (OK0: ris_ok ctx ris). {
      eapply rexec_rec_okpreserv with (ib:=(Bcond cond args ib1 ib2 iinfo)); simpl; eauto.
    }
    generalize OUT; clear OUT; simpl.
    autodestruct.
    intros COND; generalize COND.
    erewrite eval_scondition_refpreserv; eauto.
    econstructor; try_simplify_someHyps.
Qed.

Lemma rexec_correct2 ctx ib ris rfv:
  get_routcome ctx (rexec (cf ctx) ib) = Some (rout ris rfv) ->
  (ris_ok ctx ris) ->
  rst_refines ctx (rexec (cf ctx) ib) (sexec (cf ctx) ib).
Proof.
  unfold rexec; intros; eapply rexec_rec_correct2; eauto; simpl; congruence.
Qed.

Theorem rexec_simu_correct f1 f2 ib1 ib2:
  rst_simu (rexec f1 ib1) (rexec f2 ib2) ->
  symbolic_simu f1 f2 ib1 ib2.
Proof.
  intros SIMU ctx.
  eapply rst_simu_correct; eauto.
  + intros; eapply rexec_correct1; eauto.
  + intros; eapply rexec_correct2; eauto.
Qed.