-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathoptimizations_def.v
1123 lines (1017 loc) · 42.9 KB
/
optimizations_def.v
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
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Require Import bbv.Word.
Require Import Nat.
Require Import Coq.NArith.NArith.
Require Import Coq.Logic.FunctionalExtensionality.
Require Import FORVES.constants.
Import Constants.
Require Import FORVES.symbolic_state.
Import SymbolicState.
Require Import FORVES.symbolic_state_eval.
Import SymbolicStateEval.
Require Import FORVES.symbolic_state_cmp.
Import SymbolicStateCmp.
Require Import FORVES.valid_symbolic_state.
Import ValidSymbolicState.
Require Import FORVES.execution_state.
Import ExecutionState.
Require Import FORVES.stack_operation_instructions.
Import StackOpInstrs.
Require Import FORVES.program.
Import Program.
Require Import FORVES.symbolic_state_cmp_impl.
Import SymbolicStateCmpImpl.
Require Import FORVES.symbolic_state_eval_facts.
Import SymbolicStateEvalFacts.
Require Import FORVES.valid_symbolic_state.
Import ValidSymbolicState.
Require Import FORVES.misc.
Import Misc.
Require Import FORVES.eval_common.
Import EvalCommon.
Require Import FORVES.optimizations_common.
Import Optimizations_Common.
Require Import FORVES.concrete_interpreter.
Import ConcreteInterpreter.
Require Import FORVES.symbolic_state_rename.
Import SymbolicStateRename.
Require Import List.
Import ListNotations.
Module Optimizations_Def.
(* Definitions *)
Definition optim := sstate -> sstate*bool.
Definition optim_snd (opt: optim) : Prop :=
forall (sst: sstate) (sst': sstate) (b: bool),
valid_sstate sst evm_stack_opm ->
opt sst = (sst', b) ->
(valid_sstate sst' evm_stack_opm /\
get_instk_height_sst sst = get_instk_height_sst sst' /\
forall (st st': state), eval_sstate st sst evm_stack_opm = Some st' ->
eval_sstate st sst' evm_stack_opm = Some st').
(* sb2 preserves all the successful evaluations of sstack_val in sb1 *)
Definition preserv_sbindings (sb1 sb2: sbindings) (maxidx: nat)
(ops: stack_op_instr_map) (instk_height: nat) : Prop :=
valid_bindings instk_height maxidx sb1 ops /\
valid_bindings instk_height maxidx sb2 ops /\
forall (sv : sstack_val) (stk : stack) (mem: memory) (strg: storage)
(exts: externals) (v: EVMWord),
instk_height = length stk ->
eval_sstack_val sv stk mem strg exts maxidx sb1 ops = Some v ->
eval_sstack_val sv stk mem strg exts maxidx sb2 ops = Some v.
(* Type of a function that optimizes a single smap_value *)
Definition opt_smap_value_type :=
smap_value -> (* val *)
sstack_val_cmp_t -> (* fcmp *)
sbindings -> (* sb *)
nat -> (* maxid *)
nat -> (* instk_height *)
stack_op_instr_map -> (* ops *)
smap_value*bool. (* (val', flag) *)
(* Type of a function that optimizes a single smap_value and returns a new sbindings
to insert *)
Definition opt_ext_smap_value_type :=
smap_value -> (* val *)
sstack_val_cmp_t -> (* fcmp *)
sbindings -> (* sb *)
nat -> (* maxid *)
nat -> (* instk_height *)
stack_op_instr_map -> (* ops *)
smap_value*sbindings*bool. (* (val', nsb, flag) *)
Definition opt_smapv_valid_snd (opt: opt_smap_value_type) :=
forall (instk_height n: nat) (fcmp: sstack_val_cmp_t) (sb: sbindings)
(val val': smap_value) (flag: bool),
safe_sstack_val_cmp fcmp ->
valid_smap_value instk_height n evm_stack_opm val ->
valid_bindings instk_height n sb evm_stack_opm ->
opt val fcmp sb n instk_height evm_stack_opm = (val', flag) ->
valid_smap_value instk_height n evm_stack_opm val'.
(* 'opt' is sound if optimizing the head in a valid bindings (idx,val)::sb
results in a valid bindings (idx,val')::sb that preserves evaluations *)
Definition opt_sbinding_snd (opt: opt_smap_value_type) :=
forall (val val': smap_value) (fcmp: sstack_val_cmp_t) (sb: sbindings)
(maxidx: nat) (instk_height: nat) (idx: nat) (flag: bool),
safe_sstack_val_cmp fcmp ->
valid_bindings instk_height maxidx ((idx,val)::sb) evm_stack_opm ->
opt val fcmp sb idx instk_height evm_stack_opm = (val', flag) ->
valid_bindings instk_height maxidx ((idx,val')::sb) evm_stack_opm /\
forall stk mem strg exts v,
instk_height = length stk ->
eval_sstack_val (FreshVar idx) stk mem strg exts maxidx ((idx,val)::sb)
evm_stack_opm = Some v ->
eval_sstack_val (FreshVar idx) stk mem strg exts maxidx ((idx,val')::sb)
evm_stack_opm = Some v.
(* Applies smap value optimization to the first suitable entry in sbindings *)
Fixpoint optimize_first_sbindings (opt_sbinding: opt_smap_value_type)
(fcmp: sstack_val_cmp_t) (sb: sbindings) (instk_height: nat)
: sbindings*bool :=
match sb with
| [] => (sb,false)
| (n,val)::rs =>
match opt_sbinding val fcmp rs n instk_height evm_stack_opm with
| (val', true) => ((n,val')::rs, true)
| (val', false) =>
match (optimize_first_sbindings opt_sbinding fcmp rs
instk_height) with
| (rs', flag) => ((n,val)::rs', flag)
end
end
end.
Definition optimize_first_sstate (opt: opt_smap_value_type)
(fcmp: sstack_val_cmp_t) (sst: sstate)
: sstate*bool :=
match sst with
| SymExState instk_height sstk smem sstg sexts (SymMap maxid bindings) =>
match optimize_first_sbindings opt fcmp bindings instk_height with
| (bindings', flag) =>
(SymExState instk_height sstk smem sstg sexts (SymMap maxid bindings'),
flag)
end
end.
(* Changes the binding (n,_) by (n,val) in sb *)
Fixpoint replace_binding (sb: sbindings) (n: nat) (val: smap_value) : sbindings :=
match sb with
| [] => []
| (n', val')::rs => if n =? n'
then (n, val)::rs
else (n', val')::(replace_binding rs n val)
end.
(* Changes the binding (n,_) by (n,val) in sb of the state *)
Definition replace_binding_sstate (sst: sstate) (n: nat) (val: smap_value) : sstate :=
match sst with
| SymExState instk_height sstk smem sstg sexts (SymMap maxid bindings) =>
SymExState instk_height sstk smem sstg sexts (SymMap maxid (replace_binding bindings n val))
end.
(* Applies smap value optimization to the first suitable entry in sbindings, extending
the smap with possible new mappings. Returns:
* New bindings to add
* Optimized smap_value
* Index of smap_value updated, which is also the position where you need
to include the new bindings
* Flag indicating whether the optimization was applied
*)
Fixpoint optimize_ext_first_sbindings (opt_ext_sbinding: opt_ext_smap_value_type)
(fcmp: sstack_val_cmp_t) (sb: sbindings) (instk_height: nat)
: sbindings*option smap_value*nat*bool :=
match sb with
| [] => ([], None, 0, false)
| (n,val)::rs =>
match opt_ext_sbinding val fcmp rs n instk_height evm_stack_opm with
| (val', nsb, true) => (nsb, Some val', n, true)
| (_, _, false) =>
optimize_ext_first_sbindings opt_ext_sbinding fcmp rs instk_height
end
end.
Definition optimize_ext_first_sbindings_sstate' (opt_ext_sbinding: opt_ext_smap_value_type)
(fcmp: sstack_val_cmp_t) (sst: sstate)
: sbindings*option smap_value*nat*bool :=
match sst with
| SymExState instk_height sstk smem sstg sexts (SymMap maxid bindings) =>
optimize_ext_first_sbindings opt_ext_sbinding fcmp bindings instk_height
end.
Definition optimize_ext_first_sstate (opt_ext: opt_ext_smap_value_type)
(fcmp: sstack_val_cmp_t) (sst: sstate)
: sstate*bool :=
match optimize_ext_first_sbindings_sstate' opt_ext fcmp sst with
| (nsb, Some val', n, true) =>
let shift := List.length nsb in
match sstate_insert_bindings sst nsb with
| Some sst1 =>
(replace_binding_sstate sst1 (n+shift) val', true)
| _ => (sst, false)
end
| _ => (sst, false)
end.
Definition opt_ext_sbinding_snd (opt: opt_ext_smap_value_type) :=
forall (fcmp: sstack_val_cmp_t),
safe_sstack_val_cmp fcmp ->
optim_snd (optimize_ext_first_sstate opt fcmp).
(* Lemmas *)
(* sb2 preserves all the successful evaluations of sstack in sb1 *)
Lemma preserv_sbindings_sstack:
forall (sb1 sb2: sbindings) (maxidx: nat) (ops: stack_op_instr_map)
(instk_height: nat),
preserv_sbindings sb1 sb2 maxidx ops instk_height ->
forall (sstk: sstack) (stk stk': stack) (mem: memory)
(strg: storage) (exts: externals),
instk_height = length stk ->
eval_sstack sstk maxidx sb1 stk mem strg exts ops = Some stk' ->
eval_sstack sstk maxidx sb2 stk mem strg exts ops = Some stk'.
Proof.
intros sb1 sb2 maxidx ops instk_height Hpreserv sstk.
revert sb1 sb2 maxidx ops instk_height Hpreserv.
induction sstk as [|sval r IH].
- intuition.
- intros sb1 sb2 maxid ops instk_height Hpreserv stk
stk' mem strg exts Hlen Heval.
unfold preserv_sbindings in Hpreserv.
unfold eval_sstack in Heval.
unfold map_option in Heval.
destruct (eval_sstack_val sval stk mem strg exts maxid sb1 ops) as
[v|] eqn: eq_eval_sval; try discriminate.
rewrite <- map_option_ho in Heval.
assert (Hpreserv_copy := Hpreserv).
destruct Hpreserv as [Hvalid_sb1 [Hvalid_sb2 Hpreserv]].
pose proof (Hpreserv sval stk mem strg exts v Hlen eq_eval_sval)
as Heval_sval_sb2.
rewrite <- eval_sstack_def in Heval.
destruct (eval_sstack r maxid sb1 stk mem strg exts ops) as [rs_val|]
eqn: eq_eval_rs; try discriminate.
apply IH with (sb2:=sb2)(instk_height:=instk_height) in eq_eval_rs as
Heval_r_sb2; try assumption.
unfold eval_sstack.
unfold map_option.
rewrite -> Heval_sval_sb2.
rewrite <- map_option_ho.
rewrite <- eval_sstack_def.
rewrite -> Heval_r_sb2.
assumption.
Qed.
Lemma preserv_sbindings_ext: forall (sb1 sb2: sbindings)
(maxidx: nat) (ops: stack_op_instr_map) (n: nat) (smapv: smap_value)
(instk_height: nat),
maxidx = S n ->
valid_smap_value instk_height n ops smapv ->
preserv_sbindings sb1 sb2 n ops instk_height ->
preserv_sbindings ((n,smapv)::sb1) ((n,smapv)::sb2) maxidx ops instk_height.
Proof.
intros sb1 sb2 maxidx ops n smapv instk_height Hmaxidx Hvalid Hpreserv.
unfold preserv_sbindings in Hpreserv.
destruct Hpreserv as [Hvalid_sb1 [Hvalid_sb2 Hpreserv]].
unfold preserv_sbindings.
split.
- simpl. intuition.
- split.
+ simpl. intuition.
+ unfold eval_sstack_val in Hpreserv.
unfold eval_sstack_val.
intros sv stk mem strg exts v Hlen Heval.
destruct sv as [val|var|fvar] eqn: eq_sv.
* unfold eval_sstack_val. simpl.
unfold eval_sstack_val in Heval. simpl in Heval.
assumption.
* unfold eval_sstack_val. simpl.
unfold eval_sstack_val in Heval. simpl in Heval.
assumption.
* destruct (n =? fvar) eqn: eq_fvar_n.
-- destruct smapv as [basicv|tagv|label args|offset smem|key sstrg|
offset size smem] eqn: eq_smapv.
++ (* SymBasicVal basicv *)
destruct basicv as [val'|var'|fvar'] eqn: eq_basicv.
** simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
assumption.
** simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
assumption.
** rewrite -> PeanoNat.Nat.eqb_eq in eq_fvar_n.
rewrite -> eq_fvar_n in Heval.
rewrite <- eval_sstack_val'_freshvar in Heval.
rewrite -> eq_fvar_n.
rewrite <- eval_sstack_val'_freshvar.
pose proof (eval'_then_valid_sstack_value maxidx
(FreshVar fvar') stk mem strg exts maxidx sb1 ops v
instk_height n Heval Hvalid_sb1 Hlen) as Hvalid_stk_val_fv.
assert (S n > n) as maxidx_gt_nm; try intuition.
pose proof (eval_sstack_val'_succ (S n) instk_height
(FreshVar fvar') stk mem strg exts n sb1 ops Hlen
Hvalid_stk_val_fv Hvalid_sb1 maxidx_gt_nm) as eval'_fvar'.
destruct eval'_fvar' as [v' eval'_fvar'].
rewrite -> eval'_maxidx_indep_eq with (m:=n) in Heval.
pose proof (eval_sstack_val'_preserved_when_depth_extended
(S n) n sb1 (FreshVar fvar') v' stk mem strg exts ops
eval'_fvar') as eval'_fvar'_succ.
rewrite <- Hmaxidx in eval'_fvar'_succ.
rewrite -> Heval in eval'_fvar'_succ.
injection eval'_fvar'_succ as eq_v'.
rewrite <- eq_v' in eval'_fvar'.
pose proof (Hpreserv (FreshVar fvar') stk mem strg exts v Hlen
eval'_fvar') as eval'_fvar'_sb2.
rewrite -> Hmaxidx.
apply eval_sstack_val'_preserved_when_depth_extended.
rewrite -> eval'_maxidx_indep_eq with (m:=S n) in eval'_fvar'_sb2.
assumption.
++ (* SymPUSHTAG tagv *)
simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
assumption.
++ (* SymOp label args *)
rewrite <- Hmaxidx in Hpreserv.
simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
destruct (ops label) as [nargs f H_comm H_exts_ind].
destruct (length args =? nargs); try discriminate.
destruct (map_option
(fun sv' : sstack_val =>
eval_sstack_val' maxidx sv' stk mem strg exts n sb1 ops) args)
as [vargs|] eqn: Hmapo; try discriminate.
rewrite <- Heval.
pose proof (map_option_sstack maxidx stk mem strg exts n sb1 sb2
ops instk_height args vargs Hmapo Hpreserv Hlen) as eq_mapo'.
rewrite -> eq_mapo'.
reflexivity.
++ (* SymMLOAD offset smem *)
rewrite <- Hmaxidx in Hpreserv.
simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
destruct (map_option (instantiate_memory_update
(fun sv : sstack_val =>
eval_sstack_val' maxidx sv stk mem strg exts n sb1 ops)) smem)
as [mem_updates|] eqn: Hmapo; try discriminate.
pose proof (map_option_inst_mem_update maxidx stk mem strg exts n
sb1 sb2 ops instk_height smem mem_updates Hmapo Hpreserv Hlen)
as eq_mapo'.
rewrite -> eq_mapo'.
destruct (eval_sstack_val' maxidx offset stk mem strg exts n sb1 ops)
as [offsetv|] eqn: eq_eval_offset; try discriminate.
pose proof (Hpreserv offset stk mem strg exts offsetv Hlen
eq_eval_offset) as eq_eval_offset'.
rewrite -> eq_eval_offset'.
assumption.
++ (* SymSLOAD key sstrg *)
rewrite <- Hmaxidx in Hpreserv.
simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
destruct (map_option (instantiate_storage_update
(fun sv : sstack_val =>
eval_sstack_val' maxidx sv stk mem strg exts n sb1 ops)) sstrg)
as [strg_updates|] eqn: Hmapo; try discriminate.
pose proof (map_option_inst_strg_update maxidx stk mem strg exts n
sb1 sb2 ops instk_height sstrg strg_updates Hmapo Hpreserv Hlen)
as eq_mapo'.
rewrite -> eq_mapo'.
destruct (eval_sstack_val' maxidx key stk mem strg exts n sb1 ops)
as [keyv|] eqn: eq_eval_key; try discriminate.
pose proof (Hpreserv key stk mem strg exts keyv Hlen
eq_eval_key) as eq_eval_key'.
rewrite -> eq_eval_key'.
assumption.
++ (* SymSHA3 offset size smem *)
rewrite <- Hmaxidx in Hpreserv.
simpl in Heval. rewrite -> eq_fvar_n in Heval.
simpl. rewrite -> eq_fvar_n.
destruct (map_option (instantiate_memory_update
(fun sv : sstack_val =>
eval_sstack_val' maxidx sv stk mem strg exts n sb1 ops)) smem)
as [mem_updates|] eqn: Hmapo; try discriminate.
pose proof (map_option_inst_mem_update maxidx stk mem strg exts n
sb1 sb2 ops instk_height smem mem_updates Hmapo Hpreserv Hlen)
as eq_mapo'.
rewrite -> eq_mapo'.
destruct (eval_sstack_val' maxidx offset stk mem strg exts n sb1 ops)
as [offsetv|] eqn: eq_eval_offset; try discriminate.
pose proof (Hpreserv offset stk mem strg exts offsetv Hlen
eq_eval_offset) as eq_eval_offset'.
rewrite -> eq_eval_offset'.
destruct (eval_sstack_val' maxidx size stk mem strg exts n sb1 ops)
as [sizev|] eqn: eq_eval_size; try discriminate.
pose proof (Hpreserv size stk mem strg exts sizev Hlen
eq_eval_size) as eq_eval_size'.
rewrite -> eq_eval_size'.
assumption.
-- rewrite -> eval_sstack_val'_diff with (b:=n) in Heval; try assumption.
rewrite -> eval_sstack_val'_diff with (b:=n); try assumption.
pose proof (eval'_then_valid_sstack_value maxidx
(FreshVar fvar) stk mem strg exts n sb1 ops v
instk_height n Heval Hvalid_sb1 Hlen) as Hvalid_stk_val_fv.
assert (S n > n) as maxidx_gt_nm; try intuition.
pose proof (eval_sstack_val'_succ (S n) instk_height
(FreshVar fvar) stk mem strg exts n sb1 ops Hlen
Hvalid_stk_val_fv Hvalid_sb1 maxidx_gt_nm) as eval'_fvar.
destruct eval'_fvar as [v' eval'_fvar].
pose proof (eval_sstack_val'_preserved_when_depth_extended
(S n) n sb1 (FreshVar fvar) v' stk mem strg exts ops
eval'_fvar) as eval'_fvar_succ.
rewrite <- Hmaxidx in eval'_fvar_succ.
rewrite -> Heval in eval'_fvar_succ.
injection eval'_fvar_succ as eq_v'.
rewrite <- eq_v' in eval'_fvar.
pose proof (Hpreserv (FreshVar fvar) stk mem strg exts v Hlen
eval'_fvar) as eval'_fvar_sb2.
rewrite -> Hmaxidx.
apply eval_sstack_val'_preserved_when_depth_extended.
assumption.
Qed.
(* sb2 preserves all the successful evaluations of smem in sb1 *)
Lemma preserv_sbindings_smemory:
forall (sb1 sb2: sbindings) (maxidx: nat) (ops: stack_op_instr_map)
(instk_height: nat),
preserv_sbindings sb1 sb2 maxidx ops instk_height ->
forall (smem: smemory) (stk: stack) (mem mem': memory)
(strg: storage) (exts: externals),
instk_height = length stk ->
eval_smemory smem maxidx sb1 stk mem strg exts ops = Some mem' ->
eval_smemory smem maxidx sb2 stk mem strg exts ops = Some mem'.
Proof.
intros sb1 sb2 maxidx ops instk_height Hpreserv smem stk
mem mem' strg exts Hlen Heval_mem.
unfold eval_smemory. unfold eval_smemory in Heval_mem.
unfold eval_sstack_val in Hpreserv.
unfold eval_sstack_val in Heval_mem.
unfold eval_sstack_val.
destruct (map_option
(instantiate_memory_update
(fun sv : sstack_val =>
eval_sstack_val' (S maxidx) sv stk mem strg exts maxidx
sb1 ops)) smem) as [updates|] eqn: eq_mapo;
try discriminate.
injection Heval_mem as eq_mem'.
rewrite <- eq_mem'.
destruct Hpreserv as [Hvalid_sb1 [Hvalid_sb2 Hpreserv]].
pose proof (map_option_inst_mem_update (S maxidx) stk mem strg exts maxidx
sb1 sb2 ops instk_height smem updates eq_mapo Hpreserv Hlen) as eq_mapo2.
rewrite -> eq_mapo2.
reflexivity.
Qed.
(* sb2 preserves all the successful evaluations of sstorage in sb1 *)
Lemma preserv_sbindings_sstorage:
forall (sb1 sb2: sbindings) (maxidx: nat)
(ops: stack_op_instr_map) (instk_height: nat),
preserv_sbindings sb1 sb2 maxidx ops instk_height ->
forall (stk: stack) (sstrg: sstorage) (mem: memory) (strg strg': storage) (exts: externals),
instk_height = length stk ->
eval_sstorage sstrg maxidx sb1 stk mem strg exts ops = Some strg' ->
eval_sstorage sstrg maxidx sb2 stk mem strg exts ops = Some strg'.
Proof.
intros sb1 sb2 maxidx ops instk_height Hpreserv stk sstrg
mem strg strg' exts Hlen Heval_sstrg.
unfold eval_sstorage. unfold eval_sstorage in Heval_sstrg.
unfold eval_sstack_val in Hpreserv.
unfold eval_sstack_val in Heval_sstrg.
unfold eval_sstack_val.
destruct (map_option
(instantiate_storage_update
(fun sv : sstack_val =>
eval_sstack_val' (S maxidx) sv stk mem strg exts
maxidx sb1 ops)) sstrg) as [updates|] eqn: eq_mapo;
try discriminate.
injection Heval_sstrg as eq_strg'.
rewrite <- eq_strg'.
destruct Hpreserv as [Hvalid_sb1 [Hvalid_sb2 Hpreserv]].
pose proof (map_option_inst_strg_update (S maxidx) stk mem strg exts maxidx
sb1 sb2 ops instk_height sstrg updates eq_mapo Hpreserv Hlen) as eq_mapo2.
rewrite -> eq_mapo2.
reflexivity.
Qed.
(* Changing a preseving sbinding in a sstate preserves successful
evaluations *)
Lemma preserv_sbindings_sstate :
forall (sb1 sb2: sbindings) (maxidx: nat)
(ops: stack_op_instr_map) (instk_height: nat),
preserv_sbindings sb1 sb2 maxidx ops instk_height ->
valid_bindings instk_height maxidx sb1 evm_stack_opm ->
valid_bindings instk_height maxidx sb2 evm_stack_opm ->
forall (st st': state) (sstk: sstack) (smem: smemory)
(sstrg: sstorage) (sexts : sexternals),
instk_height = length (get_stack_st st) ->
eval_sstate st (SymExState instk_height sstk smem sstrg sexts
(SymMap maxidx sb1)) ops = Some st' ->
eval_sstate st (SymExState instk_height sstk smem sstrg sexts
(SymMap maxidx sb2)) ops = Some st'.
Proof.
intros sb1 sb2 maxidx ops instk_height Hpr_sbind Hvalid1 Hvalid2 st st'
sstk smem sstrg sexts Heval_sstate_sb1.
unfold eval_sstate in Heval_sstate_sb1.
simpl in Heval_sstate_sb1.
unfold eval_sstate. simpl.
destruct (instk_height =? length (get_stack_st st)) eqn: eq_instk_height;
try discriminate.
destruct (eval_sstack sstk maxidx sb1 (get_stack_st st) (get_memory_st st)
(get_storage_st st) (get_externals_st st) ops) eqn: eq_eval_sstack;
try discriminate.
apply preserv_sbindings_sstack with (sb2:=sb2)(instk_height:=instk_height) in
eq_eval_sstack; try assumption.
rewrite -> eq_eval_sstack.
destruct (eval_smemory smem maxidx sb1 (get_stack_st st) (get_memory_st st)
(get_storage_st st) (get_externals_st st) ops) eqn: eq_eval_smemory;
try discriminate.
apply preserv_sbindings_smemory with (sb2:=sb2)(instk_height:=instk_height) in
eq_eval_smemory; try assumption.
rewrite -> eq_eval_smemory.
destruct (eval_sstorage sstrg maxidx sb1 (get_stack_st st) (get_memory_st st)
(get_storage_st st) (get_externals_st st) ops) eqn: eq_eval_sstorage;
try discriminate.
apply preserv_sbindings_sstorage with (sb2:=sb2)(instk_height:=instk_height) in
eq_eval_sstorage; try assumption.
rewrite -> eq_eval_sstorage.
intuition.
Qed.
Lemma valid_smap_value_opt_sbinding_snd: forall opt val fcmp sb idx
instk_height val' flag maxidx,
opt val fcmp sb idx instk_height evm_stack_opm = (val', flag) ->
opt_sbinding_snd opt ->
safe_sstack_val_cmp fcmp ->
valid_bindings instk_height maxidx ((idx, val) :: sb) evm_stack_opm ->
valid_smap_value instk_height idx evm_stack_opm val'.
Proof.
intros opt val fcmp sb idx instk_height val' flag maxidx Hopt Hopt_snd
Hsafe_fcmp Hvalid.
unfold opt_sbinding_snd in Hopt_snd.
pose proof (Hopt_snd val val' fcmp sb maxidx instk_height idx flag
Hsafe_fcmp Hvalid Hopt) as Hopt'.
destruct Hopt' as [Hvalid' _].
unfold valid_bindings in Hvalid'.
destruct Hvalid' as [_ [Hvalid_smap _]].
assumption.
Qed.
Lemma optimize_first_valid: forall (opt: opt_smap_value_type)
(fcmp: sstack_val_cmp_t) (sb sb': sbindings) (maxid instk_height: nat)
(flag: bool),
safe_sstack_val_cmp fcmp ->
opt_sbinding_snd opt ->
valid_bindings instk_height maxid sb evm_stack_opm ->
optimize_first_sbindings opt fcmp sb instk_height = (sb', flag) ->
valid_bindings instk_height maxid sb' evm_stack_opm.
Proof.
intros opt fcmp sb. revert opt fcmp.
induction sb as [| h rsb IH].
- intros opt fcmp sb' maxid instk_height flag Hsafe_fcmp Hopt_snd Hvalid_sb
Hoptimize_first.
simpl in Hoptimize_first.
injection Hoptimize_first as eq_sb' _.
rewrite <- eq_sb'.
intuition.
- intros opt fcmp sb' maxid instk_height flag Hsafe_fcmp Hopt_snd Hvalid_sb
Hoptimize_first.
assert (Hvalid_sb_copy := Hvalid_sb).
unfold valid_bindings in Hvalid_sb.
destruct h as [idx value] eqn: eq_h.
destruct Hvalid_sb as [Hmaxid [Hvalid_smap_value Hvalid_bindings_rsb]].
fold valid_bindings in Hvalid_bindings_rsb.
simpl in Hoptimize_first.
destruct (opt value fcmp rsb idx instk_height evm_stack_opm) as [val' b]
eqn: eq_opt_value.
destruct b eqn: eq_b.
+ injection Hoptimize_first as eq_sb' eq_flag.
rewrite <- eq_sb'. simpl.
split; try assumption.
split.
* unfold opt_sbinding_snd in Hopt_snd.
pose proof (Hopt_snd value val' fcmp rsb maxid instk_height idx true
Hsafe_fcmp Hvalid_sb_copy eq_opt_value) as Hsnd_value.
destruct Hsnd_value as [Hvalid_value _].
unfold valid_bindings in Hvalid_value.
intuition.
* unfold opt_sbinding_snd in Hopt_snd.
pose proof (Hopt_snd value val' fcmp rsb maxid instk_height idx true
Hsafe_fcmp Hvalid_sb_copy eq_opt_value) as Hsnd_value.
destruct Hsnd_value as [Hvalid_value _].
unfold valid_bindings in Hvalid_value.
intuition.
+ destruct (optimize_first_sbindings opt fcmp rsb instk_height)
as [rs' flag'] eqn: eq_optimize_rsb.
injection Hoptimize_first as eq_sb' eq_flag.
rewrite <- eq_sb'. simpl.
split; try assumption.
split; try assumption.
apply IH with (opt:=opt)(fcmp:=fcmp)(flag:=flag'); try assumption.
Qed.
(* If opt is sound when optimizing the first entry in the bindings, then
the optimize_first_sbindings will preserve the bindings *)
Lemma opt_sbinding_preserves:
forall (opt: opt_smap_value_type) (fcmp: sstack_val_cmp_t) (sb sb': sbindings)
(maxid instk_height: nat) (flag: bool),
safe_sstack_val_cmp fcmp ->
opt_sbinding_snd opt ->
valid_bindings instk_height maxid sb evm_stack_opm ->
optimize_first_sbindings opt fcmp sb instk_height = (sb', flag) ->
preserv_sbindings sb sb' maxid evm_stack_opm instk_height.
Proof.
intros opt fcmp sb. revert opt fcmp.
induction sb as [|h rsb IH].
- intros opt fcmp sb' maxid instk_height flag Hfcmp_snd Hopt_sbinding_snd
Hvalid Hoptimize_first_sbindings.
simpl in Hoptimize_first_sbindings.
injection Hoptimize_first_sbindings as eq_sb' _.
rewrite <- eq_sb'.
unfold preserv_sbindings. intuition.
- intros opt fcmp sb' maxid instk_height flag Hfcmp_snd Hopt_sbinding_snd
Hvalid Hoptimize_first_sbindings.
destruct h as [n smapv] eqn: eq_h.
assert (Hoptimize_first_sbindings_copy := Hoptimize_first_sbindings).
assert (Hvalid_copy := Hvalid).
unfold optimize_first_sbindings in Hoptimize_first_sbindings.
destruct (opt smapv fcmp rsb n instk_height evm_stack_opm) as [val' b]
eqn: eq_opt_val.
unfold preserv_sbindings.
split; try assumption.
split.
* (* valid_bindings instk_height maxid sb' evm_stack_opm *)
apply optimize_first_valid with (opt:=opt)(fcmp:=fcmp)
(sb:=h::rsb)(flag:=flag); try intuition.
+ rewrite -> eq_h. assumption.
+ rewrite -> eq_h. assumption.
* destruct b eqn: eq_b.
+ (* Optimized first entry in sbindings *)
injection Hoptimize_first_sbindings as eq_sb' eq_flag'.
rewrite <- eq_sb'.
unfold preserv_sbindings.
intros sv stk mem strg exts v Hlen Heval_sb.
unfold opt_sbinding_snd in Hopt_sbinding_snd.
destruct sv as [val|var|fvar] eqn: eq_sv; try intuition.
unfold eval_sstack_val in Heval_sb.
destruct (n =? fvar) eqn: eq_n_fvar.
-- apply EqNat.beq_nat_true in eq_n_fvar.
rewrite <- eq_n_fvar in Heval_sb.
unfold eval_sstack_val in Hopt_sbinding_snd.
pose proof (Hopt_sbinding_snd smapv val' fcmp rsb maxid instk_height
n true Hfcmp_snd Hvalid eq_opt_val) as Hopt_sbinding_snd'.
destruct Hopt_sbinding_snd' as [_ Hpreserv_ext].
pose proof (Hpreserv_ext stk mem strg exts v Hlen Heval_sb).
unfold eval_sstack_val. rewrite <- eq_n_fvar.
assumption.
-- unfold eval_sstack_val.
rewrite -> eval_sstack_val'_diff with (b:=maxid); try assumption.
rewrite -> eval_sstack_val'_diff with (b:=maxid) in Heval_sb;
try assumption.
+ (* Optimized the tail of the sbindings *)
fold optimize_first_sbindings in Hoptimize_first_sbindings.
destruct (optimize_first_sbindings opt fcmp rsb instk_height) as
[rs' flag'] eqn: eq_optimize_first_rs.
injection Hoptimize_first_sbindings as eq_sb' eq_flag.
rewrite <- eq_sb'.
unfold valid_bindings in Hvalid.
destruct Hvalid as [eq_maxid_n [Hvalid_smap Hvalid_rsb]].
fold valid_bindings in Hvalid_rsb.
pose proof (IH opt fcmp rs' n instk_height flag' Hfcmp_snd
Hopt_sbinding_snd Hvalid_rsb eq_optimize_first_rs)
as Hpreserv_rs.
apply preserv_sbindings_ext; try intuition.
Qed.
Lemma optimize_first_sstate_valid: forall (opt: opt_smap_value_type)
(fcmp: sstack_val_cmp_t) (sst sst': sstate)
(flag: bool),
valid_sstate sst evm_stack_opm ->
opt_sbinding_snd opt ->
safe_sstack_val_cmp fcmp ->
optimize_first_sstate opt fcmp sst = (sst', flag) ->
valid_sstate sst' evm_stack_opm.
Proof.
intros opt fcmp sst sst' flag Hvalid Hopt Hsafe_cmp Hopt_first.
unfold valid_sstate in Hvalid.
destruct sst. destruct sm. simpl in Hvalid.
destruct Hvalid as [Hvalid_smap [Hvalid_sstack [Hvalid_smemory Hvalid_sstorage]]].
unfold optimize_first_sstate in Hopt_first.
destruct (optimize_first_sbindings opt fcmp bindings instk_height) as
[bindings' flag'] eqn: eq_optim_first.
injection Hopt_first as eq_sst' eq_flag'.
rewrite <- eq_sst'.
unfold valid_sstate. simpl.
split.
- unfold valid_smap in Hvalid_smap.
pose proof (optimize_first_valid opt fcmp bindings bindings' maxid
instk_height flag' Hsafe_cmp Hopt Hvalid_smap eq_optim_first).
assumption.
- split; try split; try assumption.
Qed.
Lemma optimize_first_sstate_preserv: forall (opt: opt_smap_value_type)
(fcmp: sstack_val_cmp_t) (sst sst': sstate)
(flag: bool),
valid_sstate sst evm_stack_opm ->
opt_sbinding_snd opt ->
safe_sstack_val_cmp fcmp ->
optimize_first_sstate opt fcmp sst = (sst', flag) ->
get_instk_height_sst sst = get_instk_height_sst sst' /\
forall (st st': state), eval_sstate st sst evm_stack_opm = Some st' ->
eval_sstate st sst' evm_stack_opm = Some st'.
Proof.
intros opt fcmp sst sst' flag Hvalid Hopt Hsafe_cmp Hopt_first.
destruct sst. destruct sm.
unfold optimize_first_sstate in Hopt_first.
destruct (optimize_first_sbindings opt fcmp bindings instk_height)
as [bindings' flag'] eqn: eq_optim_first.
injection Hopt_first as eq_sst' eq_flag.
rewrite <- eq_sst'. simpl.
split; try reflexivity.
intros st st' Heval_sst.
unfold eval_sstate in Heval_sst.
simpl in Heval_sst.
destruct (instk_height =? length (get_stack_st st)) eqn: eq_instk;
try discriminate.
destruct (eval_sstack sstk maxid bindings (get_stack_st st)
(get_memory_st st) (get_storage_st st)
(get_externals_st st) evm_stack_opm)
as [s|] eqn: eq_eval_sstack; try discriminate.
destruct (eval_smemory smem maxid bindings (get_stack_st st)
(get_memory_st st) (get_storage_st st)
(get_externals_st st) evm_stack_opm)
as [m|] eqn: eq_eval_smem; try discriminate.
destruct (eval_sstorage sstg maxid bindings (get_stack_st st)
(get_memory_st st) (get_storage_st st)
(get_externals_st st) evm_stack_opm)
as [strg|] eqn: eq_eval_strg; try discriminate.
unfold eval_sstate. simpl. rewrite -> eq_instk.
simpl in Hvalid.
unfold valid_sstate in Hvalid. simpl in Hvalid.
destruct Hvalid as [Hvalid_smap [Hvalid_sstack [Hvalid_smem Hvalid_strg]]].
unfold valid_smap in Hvalid_smap.
pose proof (opt_sbinding_preserves opt fcmp bindings bindings' maxid
instk_height flag' Hsafe_cmp Hopt Hvalid_smap eq_optim_first)
as Hpreservs_bind_bind'.
apply PeanoNat.Nat.eqb_eq in eq_instk.
pose proof (preserv_sbindings_sstack bindings bindings' maxid evm_stack_opm
instk_height Hpreservs_bind_bind' sstk (get_stack_st st) s
(get_memory_st st) (get_storage_st st) (get_externals_st st)
eq_instk eq_eval_sstack) as eq_eval_sstack'.
rewrite -> eq_eval_sstack'.
pose proof (preserv_sbindings_smemory bindings bindings' maxid evm_stack_opm
instk_height Hpreservs_bind_bind' smem (get_stack_st st) (get_memory_st st)
m (get_storage_st st) (get_externals_st st) eq_instk eq_eval_smem)
as eq_eval_smem'.
rewrite -> eq_eval_smem'.
pose proof (preserv_sbindings_sstorage bindings bindings' maxid evm_stack_opm
instk_height Hpreservs_bind_bind' (get_stack_st st) sstg (get_memory_st st)
(get_storage_st st) strg (get_externals_st st) eq_instk eq_eval_strg)
as eq_eval_strg'.
rewrite -> eq_eval_strg'.
assumption.
Qed.
Lemma instk_height_optimize_sst: forall opt fcmp sst sst' flag,
optimize_first_sstate opt fcmp sst = (sst', flag) ->
get_instk_height_sst sst = get_instk_height_sst sst'.
Proof.
intros opt fcmp sst sst' flag Hoptim.
unfold optimize_first_sstate in Hoptim.
destruct sst eqn: eq_sst. destruct sm eqn: eq_sm.
destruct (optimize_first_sbindings opt fcmp bindings instk_height)
as [bindings' flag'] eqn: eq_optim_first.
injection Hoptim as eq_sst' eq_flag.
rewrite <- eq_sst'.
reflexivity.
Qed.
Lemma optimize_first_snd_opt_snd: forall opt fcmp,
safe_sstack_val_cmp fcmp ->
opt_sbinding_snd opt ->
optim_snd (optimize_first_sstate opt fcmp).
Proof.
intros opt fcmp Hsafe_fcmp Hopt_snd.
unfold optim_snd. intros sst sst' b Hvalid_sst Hoptim.
split.
- apply optimize_first_sstate_valid with (opt:=opt)
(fcmp:=fcmp)(sst:=sst)(flag:=b); try assumption.
- split.
+ apply instk_height_optimize_sst with (opt:=opt)
(fcmp:=fcmp)(flag:=b).
assumption.
+ intros st st' Heval.
pose proof (instk_height_optimize_sst opt fcmp sst
sst' b Hoptim) as Hinstk.
pose proof (optimize_first_sstate_preserv opt fcmp sst sst' b Hvalid_sst
Hopt_snd Hsafe_fcmp Hoptim) as Hpreserv.
destruct Hpreserv as [_ Heval2_imp].
apply Heval2_imp.
assumption.
Qed.
Lemma valid_bindings_snd_opt: forall instk_height maxidx n val sb opt fcmp
val' flag,
valid_bindings instk_height maxidx ((n, val) :: sb) evm_stack_opm ->
opt_smapv_valid_snd opt ->
safe_sstack_val_cmp fcmp ->
opt val fcmp sb n instk_height evm_stack_opm = (val', flag) ->
valid_bindings instk_height maxidx ((n, val') :: sb) evm_stack_opm.
Proof.
intros instk_height maxidx n val sb opt fcmp val' flag.
intros Hvalid Hopt_smapv_snd Hfcmp Hopt.
unfold opt_smapv_valid_snd in Hopt_smapv_snd.
unfold valid_bindings in Hvalid.
unfold valid_bindings.
destruct Hvalid as [Hmaxidx [Hvalid_smapv_val Hvalid_sb]].
fold valid_bindings in Hvalid_sb.
pose proof (Hopt_smapv_snd instk_height n fcmp sb val val' flag
Hfcmp Hvalid_smapv_val Hvalid_sb Hopt) as Hvalid_smapv_val'.
split; try split; try assumption.
Qed.
(* Pipeline of sound optimizations *)
Inductive opt_entry :=
(*| OpEntry (opt: optim) (H_snd: optim_snd opt).*)
| OpEntry (opt: opt_smap_value_type) (H_snd: opt_sbinding_snd opt)
| OpExtEntry (opt: opt_ext_smap_value_type) (H_snd: opt_ext_sbinding_snd opt).
Definition opt_pipeline := list opt_entry.
(************************************************************************
Optimization strategies using optimization pipelines opt_entries and
optimizations pipelines
*************************************************************************)
(* Applies the optimization once in the first possible place inside
the bindings __of the sstate__
*)
Definition optimize_first_opt_entry_sstate (opt_e: opt_entry)
(fcmp: sstack_val_cmp_t) (sst: sstate) : sstate*bool :=
match opt_e with
| OpEntry opt Hopt_snd =>
optimize_first_sstate opt fcmp sst
| OpExtEntry opt_ext Hopt_ext_snd =>
optimize_ext_first_sstate opt_ext fcmp sst
end.
(* Applies the optimization at most n times in a sstate, stops as soon as it
does not change the sstate *)
Fixpoint apply_opt_n_times (opt_e: opt_entry) (fcmp: sstack_val_cmp_t)
(n: nat) (sst: sstate) : sstate*bool :=
match n with
| 0 => (sst, false)
| S n' =>
match optimize_first_opt_entry_sstate opt_e fcmp sst with
| (sst', true) =>
match apply_opt_n_times opt_e fcmp n' sst' with
| (sst'', b) => (sst'', true)
end
| (sst', false) => (sst', false)
end
end.
(* Improvement: extra parameter as flag accumulator for final recursion,
if needed for efficiency *)
(* Applies the pipeline in order in a sstate, applying n times each
optimization and continuing with the next one *)
Fixpoint apply_opt_n_times_pipeline_once (pipe: opt_pipeline)
(fcmp: sstack_val_cmp_t) (n: nat) (sst: sstate) : sstate*bool :=
match pipe with
| [] => (sst, false)
| opt_e::rp =>
match apply_opt_n_times opt_e fcmp n sst with
| (sst', flag1) =>
match apply_opt_n_times_pipeline_once rp fcmp n sst' with
| (sst'', flag2) => (sst'', orb flag1 flag2)
end
end
end.
(* Applies (apply_opt_n_times_pipeline n) at most k times in a sstate, stops
as soon as it does not change the sstate *)
Fixpoint apply_opt_n_times_pipeline_k (pipe: opt_pipeline)
(fcmp: sstack_val_cmp_t)
(n k: nat) (sst: sstate) : sstate*bool :=
match k with
| 0 => (sst, false)
| S k' =>
match apply_opt_n_times_pipeline_once pipe fcmp n sst with
| (sst', true) =>
match apply_opt_n_times_pipeline_k pipe fcmp n k' sst' with
| (sst'', b) => (sst'', true)
end
| (sst', false) => (sst', false)
end
end.
(* Improvement: extra parameter as flag accumulator for final recursion,
if needed for efficiency *)
Lemma optimize_first_opt_entry_sstate_snd: forall opt_e fcmp,
safe_sstack_val_cmp fcmp ->
optim_snd (optimize_first_opt_entry_sstate opt_e fcmp).
Proof.
intros opt_e fcmp Hsafe_fcmp.
destruct opt_e as [opt Hopt_snd| opt_ext Hopt_ext_snd] eqn: eq_opt_e.
* unfold optim_snd. intros sst sst' b Hvalid Hoptim_first.
unfold optimize_first_opt_entry_sstate in Hoptim_first.
+ split.
- pose proof (optimize_first_sstate_valid opt fcmp sst sst' b Hvalid
Hopt_snd Hsafe_fcmp Hoptim_first).
assumption.
- split.
++ unfold optimize_first_sstate in Hoptim_first.
destruct sst as [instk_height sstk smem sstg sexts smap] eqn: eq_sst.
destruct smap as [maxid bindings] eqn: eq_smap.
destruct (optimize_first_sbindings opt fcmp bindings instk_height).
injection Hoptim_first as eq_sst' _.
rewrite <- eq_sst'. reflexivity.
++ pose proof (optimize_first_sstate_preserv opt fcmp sst sst' b Hvalid
Hopt_snd Hsafe_fcmp Hoptim_first) as H1.
destruct H1 as [_ H2].
assumption.
* unfold opt_ext_sbinding_snd in Hopt_ext_snd.
specialize (Hopt_ext_snd fcmp Hsafe_fcmp) as H.
assumption.
Qed.
Lemma apply_opt_n_times_snd: forall opt_e fcmp n,
safe_sstack_val_cmp fcmp ->
optim_snd (apply_opt_n_times opt_e fcmp n).
Proof.
intros opt_e fcmp n. revert opt_e fcmp.
induction n as [| n' IH].
- intros opt_e fcmp Hsafe_cmp.
unfold optim_snd.
intros sst sst' b Hvalid Happly.
simpl in Happly. injection Happly as eq_sst' _.
rewrite <- eq_sst'.
split; try assumption.
split.
+ reflexivity.
+ intuition.
- intros opt_e fcmp Hsafe_cmp.
unfold optim_snd.
intros sst sst' b Hvalid Happly.
simpl in Happly.
destruct (optimize_first_opt_entry_sstate opt_e fcmp sst)
as [sst1 flag] eqn: eq_optim.
destruct flag eqn: eq_flag.
+ destruct (apply_opt_n_times opt_e fcmp n' sst1) as [sst2 flag2]
eqn: eq_apply_n'.