-
Notifications
You must be signed in to change notification settings - Fork 254
Expand file tree
/
Copy pathStackingproof.v
More file actions
2173 lines (1956 loc) · 78.8 KB
/
Stackingproof.v
File metadata and controls
2173 lines (1956 loc) · 78.8 KB
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
(* *********************************************************************)
(* *)
(* The Compcert verified compiler *)
(* *)
(* Xavier Leroy, INRIA Paris-Rocquencourt *)
(* *)
(* Copyright Institut National de Recherche en Informatique et en *)
(* Automatique. All rights reserved. This file is distributed *)
(* under the terms of the INRIA Non-Commercial License Agreement. *)
(* *)
(* *********************************************************************)
(** Correctness proof for the translation from Linear to Mach. *)
(** This file proves semantic preservation for the [Stacking] pass. *)
Require Import Coqlib Errors.
Require Import Integers AST Linking.
Require Import Values Memory Separation Events Globalenvs Smallstep.
Require Import LTL Op Locations Linear Mach.
Require Import Bounds Conventions Stacklayout Lineartyping.
Require Import Stacking.
Local Open Scope sep_scope.
Definition match_prog (p: Linear.program) (tp: Mach.program) :=
match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp.
Lemma transf_program_match:
forall p tp, transf_program p = OK tp -> match_prog p tp.
Proof.
intros. eapply match_transform_partial_program; eauto.
Qed.
(** * Basic properties of the translation *)
Lemma typesize_typesize:
forall ty, AST.typesize ty = 4 * Locations.typesize ty.
Proof.
destruct ty; auto.
Qed.
Remark size_type_chunk:
forall ty, size_chunk (chunk_of_type ty) = AST.typesize ty.
Proof.
destruct ty; reflexivity.
Qed.
Remark align_type_chunk:
forall ty, align_chunk (chunk_of_type ty) = 4 * Locations.typealign ty.
Proof.
destruct ty; reflexivity.
Qed.
Lemma slot_outgoing_argument_valid:
forall f ofs ty sg,
In (S Outgoing ofs ty) (regs_of_rpairs (loc_arguments sg)) -> slot_valid f Outgoing ofs ty = true.
Proof.
intros. exploit loc_arguments_acceptable_2; eauto. intros [A B].
unfold slot_valid. unfold proj_sumbool.
rewrite zle_true by omega.
rewrite pred_dec_true by auto.
auto.
Qed.
Lemma load_result_inject:
forall j ty v v',
Val.inject j v v' -> Val.has_type v ty -> Val.inject j v (Val.load_result (chunk_of_type ty) v').
Proof.
intros until v'; unfold Val.has_type, Val.load_result; destruct Archi.ptr64;
destruct 1; intros; auto; destruct ty; simpl;
try contradiction; try discriminate; econstructor; eauto.
Qed.
Section PRESERVATION.
Variable return_address_offset: Mach.function -> Mach.code -> ptrofs -> Prop.
Hypothesis return_address_offset_exists:
forall f sg ros c,
is_tail (Mcall sg ros :: c) (fn_code f) ->
exists ofs, return_address_offset f c ofs.
Let step := Mach.step return_address_offset.
Variable prog: Linear.program.
Variable tprog: Mach.program.
Hypothesis TRANSF: match_prog prog tprog.
Let ge := Genv.globalenv prog.
Let tge := Genv.globalenv tprog.
Section FRAME_PROPERTIES.
Variable f: Linear.function.
Let b := function_bounds f.
Let fe := make_env b.
Variable tf: Mach.function.
Hypothesis TRANSF_F: transf_function f = OK tf.
Lemma unfold_transf_function:
tf = Mach.mkfunction
f.(Linear.fn_sig)
(transl_body f fe)
fe.(fe_size)
(Ptrofs.repr fe.(fe_ofs_link))
(Ptrofs.repr fe.(fe_ofs_retaddr)).
Proof.
generalize TRANSF_F. unfold transf_function.
destruct (wt_function f); simpl negb.
destruct (zlt Ptrofs.max_unsigned (fe_size (make_env (function_bounds f)))).
intros; discriminate.
intros. unfold fe. unfold b. congruence.
intros; discriminate.
Qed.
Lemma transf_function_well_typed:
wt_function f = true.
Proof.
generalize TRANSF_F. unfold transf_function.
destruct (wt_function f); simpl negb. auto. intros; discriminate.
Qed.
Lemma size_no_overflow: fe.(fe_size) <= Ptrofs.max_unsigned.
Proof.
generalize TRANSF_F. unfold transf_function.
destruct (wt_function f); simpl negb.
destruct (zlt Ptrofs.max_unsigned (fe_size (make_env (function_bounds f)))).
intros; discriminate.
intros. unfold fe. unfold b. omega.
intros; discriminate.
Qed.
Remark bound_stack_data_stacksize:
f.(Linear.fn_stacksize) <= b.(bound_stack_data).
Proof.
unfold b, function_bounds, bound_stack_data. apply Z.le_max_l.
Qed.
(** * Memory assertions used to describe the contents of stack frames *)
Local Opaque Z.add Z.mul Z.divide.
(** Accessing the stack frame using [load_stack] and [store_stack]. *)
Lemma contains_get_stack:
forall spec m ty sp ofs,
m |= contains (chunk_of_type ty) sp ofs spec ->
exists v, load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr ofs) = Some v /\ spec v.
Proof.
intros. unfold load_stack.
replace (Val.offset_ptr (Vptr sp Ptrofs.zero) (Ptrofs.repr ofs)) with (Vptr sp (Ptrofs.repr ofs)).
eapply loadv_rule; eauto.
simpl. rewrite Ptrofs.add_zero_l; auto.
Qed.
Lemma hasvalue_get_stack:
forall ty m sp ofs v,
m |= hasvalue (chunk_of_type ty) sp ofs v ->
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr ofs) = Some v.
Proof.
intros. exploit contains_get_stack; eauto. intros (v' & A & B). congruence.
Qed.
Lemma contains_set_stack:
forall (spec: val -> Prop) v spec1 m ty sp ofs P,
m |= contains (chunk_of_type ty) sp ofs spec1 ** P ->
spec (Val.load_result (chunk_of_type ty) v) ->
exists m',
store_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr ofs) v = Some m'
/\ m' |= contains (chunk_of_type ty) sp ofs spec ** P.
Proof.
intros. unfold store_stack.
replace (Val.offset_ptr (Vptr sp Ptrofs.zero) (Ptrofs.repr ofs)) with (Vptr sp (Ptrofs.repr ofs)).
eapply storev_rule; eauto.
simpl. rewrite Ptrofs.add_zero_l; auto.
Qed.
(** [contains_locations j sp pos bound sl ls] is a separation logic assertion
that holds if the memory area at block [sp], offset [pos], size [4 * bound],
reflects the values of the stack locations of kind [sl] given by the
location map [ls], up to the memory injection [j].
Two such [contains_locations] assertions will be used later, one to
reason about the values of [Local] slots, the other about the values of
[Outgoing] slots. *)
Program Definition contains_locations (j: meminj) (sp: block) (pos bound: Z) (sl: slot) (ls: locset) : massert := {|
m_pred := fun m =>
(8 | pos) /\ 0 <= pos /\ pos + 4 * bound <= Ptrofs.modulus /\
Mem.range_perm m sp pos (pos + 4 * bound) Cur Freeable /\
forall ofs ty, 0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
exists v, Mem.load (chunk_of_type ty) m sp (pos + 4 * ofs) = Some v
/\ Val.inject j (ls (S sl ofs ty)) v;
m_footprint := fun b ofs =>
b = sp /\ pos <= ofs < pos + 4 * bound
|}.
Next Obligation.
intuition auto.
- red; intros. eapply Mem.perm_unchanged_on; eauto. simpl; auto.
- exploit H4; eauto. intros (v & A & B). exists v; split; auto.
eapply Mem.load_unchanged_on; eauto.
simpl; intros. rewrite size_type_chunk, typesize_typesize in H8.
split; auto. omega.
Qed.
Next Obligation.
eauto with mem.
Qed.
Remark valid_access_location:
forall m sp pos bound ofs ty p,
(8 | pos) ->
Mem.range_perm m sp pos (pos + 4 * bound) Cur Freeable ->
0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
Mem.valid_access m (chunk_of_type ty) sp (pos + 4 * ofs) p.
Proof.
intros; split.
- red; intros. apply Mem.perm_implies with Freeable; auto with mem.
apply H0. rewrite size_type_chunk, typesize_typesize in H4. omega.
- rewrite align_type_chunk. apply Z.divide_add_r.
apply Z.divide_trans with 8; auto.
exists (8 / (4 * typealign ty)); destruct ty; reflexivity.
apply Z.mul_divide_mono_l. auto.
Qed.
Lemma get_location:
forall m j sp pos bound sl ls ofs ty,
m |= contains_locations j sp pos bound sl ls ->
0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
exists v,
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (pos + 4 * ofs)) = Some v
/\ Val.inject j (ls (S sl ofs ty)) v.
Proof.
intros. destruct H as (D & E & F & G & H).
exploit H; eauto. intros (v & U & V). exists v; split; auto.
unfold load_stack; simpl. rewrite Ptrofs.add_zero_l, Ptrofs.unsigned_repr; auto.
unfold Ptrofs.max_unsigned. generalize (typesize_pos ty). omega.
Qed.
Lemma set_location:
forall m j sp pos bound sl ls P ofs ty v v',
m |= contains_locations j sp pos bound sl ls ** P ->
0 <= ofs -> ofs + typesize ty <= bound -> (typealign ty | ofs) ->
Val.inject j v v' ->
exists m',
store_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (pos + 4 * ofs)) v' = Some m'
/\ m' |= contains_locations j sp pos bound sl (Locmap.set (S sl ofs ty) v ls) ** P.
Proof.
intros. destruct H as (A & B & C). destruct A as (D & E & F & G & H).
edestruct Mem.valid_access_store as [m' STORE].
eapply valid_access_location; eauto.
assert (PERM: Mem.range_perm m' sp pos (pos + 4 * bound) Cur Freeable).
{ red; intros; eauto with mem. }
exists m'; split.
- unfold store_stack; simpl. rewrite Ptrofs.add_zero_l, Ptrofs.unsigned_repr; eauto.
unfold Ptrofs.max_unsigned. generalize (typesize_pos ty). omega.
- simpl. intuition auto.
+ unfold Locmap.set.
destruct (Loc.eq (S sl ofs ty) (S sl ofs0 ty0)); [|destruct (Loc.diff_dec (S sl ofs ty) (S sl ofs0 ty0))].
* (* same location *)
inv e. rename ofs0 into ofs. rename ty0 into ty.
exists (Val.load_result (chunk_of_type ty) v'); split.
eapply Mem.load_store_similar_2; eauto. omega.
apply Val.load_result_inject; auto.
* (* different locations *)
exploit H; eauto. intros (v0 & X & Y). exists v0; split; auto.
rewrite <- X; eapply Mem.load_store_other; eauto.
destruct d. congruence. right. rewrite ! size_type_chunk, ! typesize_typesize. omega.
* (* overlapping locations *)
destruct (Mem.valid_access_load m' (chunk_of_type ty0) sp (pos + 4 * ofs0)) as [v'' LOAD].
apply Mem.valid_access_implies with Writable; auto with mem.
eapply valid_access_location; eauto.
exists v''; auto.
+ apply (m_invar P) with m; auto.
eapply Mem.store_unchanged_on; eauto.
intros i; rewrite size_type_chunk, typesize_typesize. intros; red; intros.
eelim C; eauto. simpl. split; auto. omega.
Qed.
Lemma initial_locations:
forall j sp pos bound P sl ls m,
m |= range sp pos (pos + 4 * bound) ** P ->
(8 | pos) ->
(forall ofs ty, ls (S sl ofs ty) = Vundef) ->
m |= contains_locations j sp pos bound sl ls ** P.
Proof.
intros. destruct H as (A & B & C). destruct A as (D & E & F). split.
- simpl; intuition auto. red; intros; eauto with mem.
destruct (Mem.valid_access_load m (chunk_of_type ty) sp (pos + 4 * ofs)) as [v LOAD].
eapply valid_access_location; eauto.
red; intros; eauto with mem.
exists v; split; auto. rewrite H1; auto.
- split; assumption.
Qed.
Lemma contains_locations_exten:
forall ls ls' j sp pos bound sl,
(forall ofs ty, Val.lessdef (ls' (S sl ofs ty)) (ls (S sl ofs ty))) ->
massert_imp (contains_locations j sp pos bound sl ls)
(contains_locations j sp pos bound sl ls').
Proof.
intros; split; simpl; intros; auto.
intuition auto. exploit H5; eauto. intros (v & A & B). exists v; split; auto.
specialize (H ofs ty). inv H. congruence. auto.
Qed.
Lemma contains_locations_incr:
forall j j' sp pos bound sl ls,
inject_incr j j' ->
massert_imp (contains_locations j sp pos bound sl ls)
(contains_locations j' sp pos bound sl ls).
Proof.
intros; split; simpl; intros; auto.
intuition auto. exploit H5; eauto. intros (v & A & B). exists v; eauto.
Qed.
(** [contains_callee_saves j sp pos rl ls] is a memory assertion that holds
if block [sp], starting at offset [pos], contains the values of the
callee-save registers [rl] as given by the location map [ls],
up to the memory injection [j]. The memory layout of the registers in [rl]
is the same as that implemented by [save_callee_save_rec]. *)
Fixpoint contains_callee_saves (j: meminj) (sp: block) (pos: Z) (rl: list mreg) (ls: locset) : massert :=
match rl with
| nil => pure True
| r :: rl =>
let ty := mreg_type r in
let sz := AST.typesize ty in
let pos1 := align pos sz in
contains (chunk_of_type ty) sp pos1 (fun v => Val.inject j (ls (R r)) v)
** contains_callee_saves j sp (pos1 + sz) rl ls
end.
Lemma contains_callee_saves_incr:
forall j j' sp ls,
inject_incr j j' ->
forall rl pos,
massert_imp (contains_callee_saves j sp pos rl ls)
(contains_callee_saves j' sp pos rl ls).
Proof.
induction rl as [ | r1 rl]; simpl; intros.
- reflexivity.
- apply sepconj_morph_1; auto. apply contains_imp. eauto.
Qed.
Lemma contains_callee_saves_exten:
forall j sp ls ls' rl pos,
(forall r, In r rl -> ls' (R r) = ls (R r)) ->
massert_eqv (contains_callee_saves j sp pos rl ls)
(contains_callee_saves j sp pos rl ls').
Proof.
induction rl as [ | r1 rl]; simpl; intros.
- reflexivity.
- apply sepconj_morph_2; auto. rewrite H by auto. reflexivity.
Qed.
(** Separation logic assertions describing the stack frame at [sp].
It must contain:
- the values of the [Local] stack slots of [ls], as per [contains_locations]
- the values of the [Outgoing] stack slots of [ls], as per [contains_locations]
- the [parent] pointer representing the back link to the caller's frame
- the [retaddr] pointer representing the saved return address
- the initial values of the used callee-save registers as given by [ls0],
as per [contains_callee_saves].
In addition, we use a nonseparating conjunction to record the fact that
we have full access rights on the stack frame, except the part that
represents the Linear stack data. *)
Definition frame_contents_1 (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
contains_locations j sp fe.(fe_ofs_local) b.(bound_local) Local ls
** contains_locations j sp fe_ofs_arg b.(bound_outgoing) Outgoing ls
** hasvalue Mptr sp fe.(fe_ofs_link) parent
** hasvalue Mptr sp fe.(fe_ofs_retaddr) retaddr
** contains_callee_saves j sp fe.(fe_ofs_callee_save) b.(used_callee_save) ls0.
Definition frame_contents (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
mconj (frame_contents_1 j sp ls ls0 parent retaddr)
(range sp 0 fe.(fe_stack_data) **
range sp (fe.(fe_stack_data) + b.(bound_stack_data)) fe.(fe_size)).
(** Accessing components of the frame. *)
Lemma frame_get_local:
forall ofs ty j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
exists v,
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_local fe ofs)) = Some v
/\ Val.inject j (ls (S Local ofs ty)) v.
Proof.
unfold frame_contents, frame_contents_1; intros. unfold slot_valid in H1; InvBooleans.
apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_proj1 in H.
eapply get_location; eauto.
Qed.
Lemma frame_get_outgoing:
forall ofs ty j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
exists v,
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_arg ofs)) = Some v
/\ Val.inject j (ls (S Outgoing ofs ty)) v.
Proof.
unfold frame_contents, frame_contents_1; intros. unfold slot_valid in H1; InvBooleans.
apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick2 in H.
eapply get_location; eauto.
Qed.
Lemma frame_get_parent:
forall j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
load_stack m (Vptr sp Ptrofs.zero) Tptr (Ptrofs.repr fe.(fe_ofs_link)) = Some parent.
Proof.
unfold frame_contents, frame_contents_1; intros.
apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick3 in H. rewrite <- chunk_of_Tptr in H.
eapply hasvalue_get_stack; eauto.
Qed.
Lemma frame_get_retaddr:
forall j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
load_stack m (Vptr sp Ptrofs.zero) Tptr (Ptrofs.repr fe.(fe_ofs_retaddr)) = Some retaddr.
Proof.
unfold frame_contents, frame_contents_1; intros.
apply mconj_proj1 in H. apply sep_proj1 in H. apply sep_pick4 in H. rewrite <- chunk_of_Tptr in H.
eapply hasvalue_get_stack; eauto.
Qed.
(** Assigning a [Local] or [Outgoing] stack slot. *)
Lemma frame_set_local:
forall ofs ty v v' j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
Val.inject j v v' ->
exists m',
store_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_local fe ofs)) v' = Some m'
/\ m' |= frame_contents j sp (Locmap.set (S Local ofs ty) v ls) ls0 parent retaddr ** P.
Proof.
intros. unfold frame_contents in H.
exploit mconj_proj1; eauto. unfold frame_contents_1.
rewrite ! sep_assoc; intros SEP.
unfold slot_valid in H1; InvBooleans. simpl in H0.
exploit set_location; eauto. intros (m' & A & B).
exists m'; split; auto.
assert (forall i k p, Mem.perm m sp i k p -> Mem.perm m' sp i k p).
{ intros. unfold store_stack in A; simpl in A. eapply Mem.perm_store_1; eauto. }
eapply frame_mconj. eauto.
unfold frame_contents_1; rewrite ! sep_assoc; exact B.
eapply sep_preserved.
eapply sep_proj1. eapply mconj_proj2. eassumption.
intros; eapply range_preserved; eauto.
intros; eapply range_preserved; eauto.
Qed.
Lemma frame_set_outgoing:
forall ofs ty v v' j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Outgoing ofs ty -> slot_valid f Outgoing ofs ty = true ->
Val.inject j v v' ->
exists m',
store_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_arg ofs)) v' = Some m'
/\ m' |= frame_contents j sp (Locmap.set (S Outgoing ofs ty) v ls) ls0 parent retaddr ** P.
Proof.
intros. unfold frame_contents in H.
exploit mconj_proj1; eauto. unfold frame_contents_1.
rewrite ! sep_assoc, sep_swap. intros SEP.
unfold slot_valid in H1; InvBooleans. simpl in H0.
exploit set_location; eauto. intros (m' & A & B).
exists m'; split; auto.
assert (forall i k p, Mem.perm m sp i k p -> Mem.perm m' sp i k p).
{ intros. unfold store_stack in A; simpl in A. eapply Mem.perm_store_1; eauto. }
eapply frame_mconj. eauto.
unfold frame_contents_1; rewrite ! sep_assoc, sep_swap; eauto.
eapply sep_preserved.
eapply sep_proj1. eapply mconj_proj2. eassumption.
intros; eapply range_preserved; eauto.
intros; eapply range_preserved; eauto.
Qed.
(** Invariance by change of location maps. *)
Lemma frame_contents_exten:
forall ls ls0 ls' ls0' j sp parent retaddr P m,
(forall ofs ty, Val.lessdef (ls' (S Local ofs ty)) (ls (S Local ofs ty))) ->
(forall ofs ty, Val.lessdef (ls' (S Outgoing ofs ty)) (ls (S Outgoing ofs ty))) ->
(forall r, In r b.(used_callee_save) -> ls0' (R r) = ls0 (R r)) ->
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
m |= frame_contents j sp ls' ls0' parent retaddr ** P.
Proof.
unfold frame_contents, frame_contents_1; intros.
rewrite <- ! (contains_locations_exten ls ls') by auto.
erewrite <- contains_callee_saves_exten by eauto.
assumption.
Qed.
(** Invariance by assignment to registers. *)
Corollary frame_set_reg:
forall r v j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
m |= frame_contents j sp (Locmap.set (R r) v ls) ls0 parent retaddr ** P.
Proof.
intros. apply frame_contents_exten with ls ls0; auto.
Qed.
Corollary frame_undef_regs:
forall j sp ls ls0 parent retaddr m P rl,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
m |= frame_contents j sp (LTL.undef_regs rl ls) ls0 parent retaddr ** P.
Proof.
Local Opaque sepconj.
induction rl; simpl; intros.
- auto.
- apply frame_set_reg; auto.
Qed.
Corollary frame_set_regpair:
forall j sp ls0 parent retaddr m P p v ls,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
m |= frame_contents j sp (Locmap.setpair p v ls) ls0 parent retaddr ** P.
Proof.
intros. destruct p; simpl.
apply frame_set_reg; auto.
apply frame_set_reg; apply frame_set_reg; auto.
Qed.
Corollary frame_set_res:
forall j sp ls0 parent retaddr m P res v ls,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
m |= frame_contents j sp (Locmap.setres res v ls) ls0 parent retaddr ** P.
Proof.
induction res; simpl; intros.
- apply frame_set_reg; auto.
- auto.
- eauto.
Qed.
(** Invariance by change of memory injection. *)
Lemma frame_contents_incr:
forall j sp ls ls0 parent retaddr m P j',
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
inject_incr j j' ->
m |= frame_contents j' sp ls ls0 parent retaddr ** P.
Proof.
unfold frame_contents, frame_contents_1; intros.
rewrite <- (contains_locations_incr j j') by auto.
rewrite <- (contains_locations_incr j j') by auto.
erewrite <- contains_callee_saves_incr by eauto.
assumption.
Qed.
(** * Agreement between location sets and Mach states *)
(** Agreement with Mach register states *)
Definition agree_regs (j: meminj) (ls: locset) (rs: regset) : Prop :=
forall r, Val.inject j (ls (R r)) (rs r).
(** Agreement over locations *)
Record agree_locs (ls ls0: locset) : Prop :=
mk_agree_locs {
(** Unused registers have the same value as in the caller *)
agree_unused_reg:
forall r, ~(mreg_within_bounds b r) -> ls (R r) = ls0 (R r);
(** Incoming stack slots have the same value as the
corresponding Outgoing stack slots in the caller *)
agree_incoming:
forall ofs ty,
In (S Incoming ofs ty) (regs_of_rpairs (loc_parameters f.(Linear.fn_sig))) ->
ls (S Incoming ofs ty) = ls0 (S Outgoing ofs ty)
}.
(** ** Properties of [agree_regs]. *)
(** Values of registers *)
Lemma agree_reg:
forall j ls rs r,
agree_regs j ls rs -> Val.inject j (ls (R r)) (rs r).
Proof.
intros. auto.
Qed.
Lemma agree_reglist:
forall j ls rs rl,
agree_regs j ls rs -> Val.inject_list j (reglist ls rl) (rs##rl).
Proof.
induction rl; simpl; intros.
auto. constructor; auto using agree_reg.
Qed.
Hint Resolve agree_reg agree_reglist: stacking.
(** Preservation under assignments of machine registers. *)
Lemma agree_regs_set_reg:
forall j ls rs r v v',
agree_regs j ls rs ->
Val.inject j v v' ->
agree_regs j (Locmap.set (R r) v ls) (Regmap.set r v' rs).
Proof.
intros; red; intros.
unfold Regmap.set. destruct (RegEq.eq r0 r). subst r0.
rewrite Locmap.gss; auto.
rewrite Locmap.gso; auto. red. auto.
Qed.
Lemma agree_regs_set_pair:
forall j p v v' ls rs,
agree_regs j ls rs ->
Val.inject j v v' ->
agree_regs j (Locmap.setpair p v ls) (set_pair p v' rs).
Proof.
intros. destruct p; simpl.
- apply agree_regs_set_reg; auto.
- apply agree_regs_set_reg. apply agree_regs_set_reg; auto.
apply Val.hiword_inject; auto. apply Val.loword_inject; auto.
Qed.
Lemma agree_regs_set_res:
forall j res v v' ls rs,
agree_regs j ls rs ->
Val.inject j v v' ->
agree_regs j (Locmap.setres res v ls) (set_res res v' rs).
Proof.
induction res; simpl; intros.
- apply agree_regs_set_reg; auto.
- auto.
- apply IHres2. apply IHres1. auto.
apply Val.hiword_inject; auto.
apply Val.loword_inject; auto.
Qed.
Lemma agree_regs_exten:
forall j ls rs ls' rs',
agree_regs j ls rs ->
(forall r, ls' (R r) = Vundef \/ ls' (R r) = ls (R r) /\ rs' r = rs r) ->
agree_regs j ls' rs'.
Proof.
intros; red; intros.
destruct (H0 r) as [A | [A B]].
rewrite A. constructor.
rewrite A; rewrite B; auto.
Qed.
Lemma agree_regs_undef_regs:
forall j rl ls rs,
agree_regs j ls rs ->
agree_regs j (LTL.undef_regs rl ls) (Mach.undef_regs rl rs).
Proof.
induction rl; simpl; intros.
auto.
apply agree_regs_set_reg; auto.
Qed.
Lemma agree_regs_undef_caller_save_regs:
forall j ls rs,
agree_regs j ls rs ->
agree_regs j (LTL.undef_caller_save_regs ls) (Mach.undef_caller_save_regs rs).
Proof.
intros; red; intros.
unfold LTL.undef_caller_save_regs, Mach.undef_caller_save_regs.
destruct (is_callee_save r); auto.
Qed.
(** Preservation under assignment of stack slot *)
Lemma agree_regs_set_slot:
forall j ls rs sl ofs ty v,
agree_regs j ls rs ->
agree_regs j (Locmap.set (S sl ofs ty) v ls) rs.
Proof.
intros; red; intros. rewrite Locmap.gso; auto. red. auto.
Qed.
(** Preservation by increasing memory injections *)
Lemma agree_regs_inject_incr:
forall j ls rs j',
agree_regs j ls rs -> inject_incr j j' -> agree_regs j' ls rs.
Proof.
intros; red; intros; eauto with stacking.
Qed.
(** Preservation at function entry. *)
Lemma agree_regs_call_regs:
forall j ls rs,
agree_regs j ls rs ->
agree_regs j (call_regs ls) rs.
Proof.
intros.
unfold call_regs; intros; red; intros; auto.
Qed.
(** ** Properties of [agree_locs] *)
(** Preservation under assignment of machine register. *)
Lemma agree_locs_set_reg:
forall ls ls0 r v,
agree_locs ls ls0 ->
mreg_within_bounds b r ->
agree_locs (Locmap.set (R r) v ls) ls0.
Proof.
intros. inv H; constructor; auto; intros.
rewrite Locmap.gso. auto. red. intuition congruence.
Qed.
Lemma caller_save_reg_within_bounds:
forall r,
is_callee_save r = false -> mreg_within_bounds b r.
Proof.
intros; red; intros. congruence.
Qed.
Lemma agree_locs_set_pair:
forall ls0 p v ls,
agree_locs ls ls0 ->
forall_rpair (fun r => is_callee_save r = false) p ->
agree_locs (Locmap.setpair p v ls) ls0.
Proof.
intros.
destruct p; simpl in *.
apply agree_locs_set_reg; auto. apply caller_save_reg_within_bounds; auto.
destruct H0.
apply agree_locs_set_reg; auto. apply agree_locs_set_reg; auto.
apply caller_save_reg_within_bounds; auto. apply caller_save_reg_within_bounds; auto.
Qed.
Lemma agree_locs_set_res:
forall ls0 res v ls,
agree_locs ls ls0 ->
(forall r, In r (params_of_builtin_res res) -> mreg_within_bounds b r) ->
agree_locs (Locmap.setres res v ls) ls0.
Proof.
induction res; simpl; intros.
- eapply agree_locs_set_reg; eauto.
- auto.
- apply IHres2; auto using in_or_app.
Qed.
Lemma agree_locs_undef_regs:
forall ls0 regs ls,
agree_locs ls ls0 ->
(forall r, In r regs -> mreg_within_bounds b r) ->
agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
induction regs; simpl; intros.
auto.
apply agree_locs_set_reg; auto.
Qed.
Lemma agree_locs_undef_locs_1:
forall ls0 regs ls,
agree_locs ls ls0 ->
(forall r, In r regs -> is_callee_save r = false) ->
agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
intros. eapply agree_locs_undef_regs; eauto.
intros. apply caller_save_reg_within_bounds. auto.
Qed.
Lemma agree_locs_undef_locs:
forall ls0 regs ls,
agree_locs ls ls0 ->
existsb is_callee_save regs = false ->
agree_locs (LTL.undef_regs regs ls) ls0.
Proof.
intros. eapply agree_locs_undef_locs_1; eauto.
intros. destruct (is_callee_save r) eqn:CS; auto.
assert (existsb is_callee_save regs = true).
{ apply existsb_exists. exists r; auto. }
congruence.
Qed.
(** Preservation by assignment to local slot *)
Lemma agree_locs_set_slot:
forall ls ls0 sl ofs ty v,
agree_locs ls ls0 ->
slot_writable sl = true ->
agree_locs (Locmap.set (S sl ofs ty) v ls) ls0.
Proof.
intros. destruct H; constructor; intros.
- rewrite Locmap.gso; auto. red; auto.
- rewrite Locmap.gso; auto. red. left. destruct sl; discriminate.
Qed.
(** Preservation at return points (when [ls] is changed but not [ls0]). *)
Lemma agree_locs_return:
forall ls ls0 ls',
agree_locs ls ls0 ->
agree_callee_save ls' ls ->
agree_locs ls' ls0.
Proof.
intros. red in H0. inv H; constructor; auto; intros.
- rewrite H0; auto. unfold mreg_within_bounds in H. tauto.
- rewrite <- agree_incoming0 by auto. apply H0. congruence.
Qed.
(** ** Properties of destroyed registers. *)
Definition no_callee_saves (l: list mreg) : Prop :=
existsb is_callee_save l = false.
Remark destroyed_by_op_caller_save:
forall op, no_callee_saves (destroyed_by_op op).
Proof.
unfold no_callee_saves; destruct op; (reflexivity || destruct c; reflexivity).
Qed.
Remark destroyed_by_load_caller_save:
forall chunk addr, no_callee_saves (destroyed_by_load chunk addr).
Proof.
unfold no_callee_saves; destruct chunk; reflexivity.
Qed.
Remark destroyed_by_store_caller_save:
forall chunk addr, no_callee_saves (destroyed_by_store chunk addr).
Proof.
Local Transparent destroyed_by_store.
unfold no_callee_saves, destroyed_by_store; intros; destruct chunk; try reflexivity; destruct Archi.ptr64; reflexivity.
Qed.
Remark destroyed_by_cond_caller_save:
forall cond, no_callee_saves (destroyed_by_cond cond).
Proof.
unfold no_callee_saves; destruct cond; reflexivity.
Qed.
Remark destroyed_by_jumptable_caller_save:
no_callee_saves destroyed_by_jumptable.
Proof.
red; reflexivity.
Qed.
Remark destroyed_by_setstack_caller_save:
forall ty, no_callee_saves (destroyed_by_setstack ty).
Proof.
unfold no_callee_saves; destruct ty; reflexivity.
Qed.
Remark destroyed_at_function_entry_caller_save:
no_callee_saves destroyed_at_function_entry.
Proof.
red; reflexivity.
Qed.
Hint Resolve destroyed_by_op_caller_save destroyed_by_load_caller_save
destroyed_by_store_caller_save
destroyed_by_cond_caller_save destroyed_by_jumptable_caller_save
destroyed_at_function_entry_caller_save: stacking.
Remark destroyed_by_setstack_function_entry:
forall ty, incl (destroyed_by_setstack ty) destroyed_at_function_entry.
Proof.
Local Transparent destroyed_by_setstack destroyed_at_function_entry.
unfold incl; destruct ty; simpl; tauto.
Qed.
Remark transl_destroyed_by_op:
forall op e, destroyed_by_op (transl_op e op) = destroyed_by_op op.
Proof.
intros; destruct op; reflexivity.
Qed.
Remark transl_destroyed_by_load:
forall chunk addr e, destroyed_by_load chunk (transl_addr e addr) = destroyed_by_load chunk addr.
Proof.
intros; destruct chunk; reflexivity.
Qed.
Remark transl_destroyed_by_store:
forall chunk addr e, destroyed_by_store chunk (transl_addr e addr) = destroyed_by_store chunk addr.
Proof.
intros; destruct chunk; reflexivity.
Qed.
(** * Correctness of saving and restoring of callee-save registers *)
(** The following lemmas show the correctness of the register saving
code generated by [save_callee_save]: after this code has executed,
the register save areas of the current frame do contain the
values of the callee-save registers used by the function. *)
Section SAVE_CALLEE_SAVE.
Variable j: meminj.
Variable cs: list stackframe.
Variable fb: block.
Variable sp: block.
Variable ls: locset.
Hypothesis ls_temp_undef:
forall ty r, In r (destroyed_by_setstack ty) -> ls (R r) = Vundef.
Hypothesis wt_ls: forall r, Val.has_type (ls (R r)) (mreg_type r).
Lemma save_callee_save_rec_correct:
forall k l pos rs m P,
(forall r, In r l -> is_callee_save r = true) ->
m |= range sp pos (size_callee_save_area_rec l pos) ** P ->
agree_regs j ls rs ->
exists rs', exists m',
star step tge
(State cs fb (Vptr sp Ptrofs.zero) (save_callee_save_rec l pos k) rs m)
E0 (State cs fb (Vptr sp Ptrofs.zero) k rs' m')
/\ m' |= contains_callee_saves j sp pos l ls ** P
/\ (forall ofs k p, Mem.perm m sp ofs k p -> Mem.perm m' sp ofs k p)
/\ agree_regs j ls rs'.
Proof.
Local Opaque mreg_type.
induction l as [ | r l]; simpl; intros until P; intros CS SEP AG.
- exists rs, m.
split. apply star_refl.
split. rewrite sep_pure; split; auto. eapply sep_drop; eauto.
split. auto.
auto.
- set (ty := mreg_type r) in *.
set (sz := AST.typesize ty) in *.
set (pos1 := align pos sz) in *.
assert (SZPOS: sz > 0) by (apply AST.typesize_pos).
assert (SZREC: pos1 + sz <= size_callee_save_area_rec l (pos1 + sz)) by (apply size_callee_save_area_rec_incr).
assert (POS1: pos <= pos1) by (apply align_le; auto).
assert (AL1: (align_chunk (chunk_of_type ty) | pos1)).
{ unfold pos1. apply Z.divide_trans with sz.
unfold sz; rewrite <- size_type_chunk. apply align_size_chunk_divides.
apply align_divides; auto. }
apply range_drop_left with (mid := pos1) in SEP; [ | omega ].
apply range_split with (mid := pos1 + sz) in SEP; [ | omega ].
unfold sz at 1 in SEP. rewrite <- size_type_chunk in SEP.
apply range_contains in SEP; auto.
exploit (contains_set_stack (fun v' => Val.inject j (ls (R r)) v') (rs r)).
eexact SEP.
apply load_result_inject; auto. apply wt_ls.
clear SEP; intros (m1 & STORE & SEP).
set (rs1 := undef_regs (destroyed_by_setstack ty) rs).
assert (AG1: agree_regs j ls rs1).
{ red; intros. unfold rs1. destruct (In_dec mreg_eq r0 (destroyed_by_setstack ty)).
erewrite ls_temp_undef by eauto. auto.
rewrite undef_regs_other by auto. apply AG. }
rewrite sep_swap in SEP.
exploit (IHl (pos1 + sz) rs1 m1); eauto.
intros (rs2 & m2 & A & B & C & D).
exists rs2, m2.
split. eapply star_left; eauto. constructor. exact STORE. auto. traceEq.
split. rewrite sep_assoc, sep_swap. exact B.
split. intros. apply C. unfold store_stack in STORE; simpl in STORE. eapply Mem.perm_store_1; eauto.
auto.
Qed.
End SAVE_CALLEE_SAVE.
Remark LTL_undef_regs_same:
forall r rl ls, In r rl -> LTL.undef_regs rl ls (R r) = Vundef.
Proof.
induction rl; simpl; intros. contradiction.
unfold Locmap.set. destruct (Loc.eq (R a) (R r)). auto.
destruct (Loc.diff_dec (R a) (R r)); auto.
apply IHrl. intuition congruence.
Qed.
Remark LTL_undef_regs_others:
forall r rl ls, ~In r rl -> LTL.undef_regs rl ls (R r) = ls (R r).
Proof.
induction rl; simpl; intros. auto.
rewrite Locmap.gso. apply IHrl. intuition. red. intuition.
Qed.
Remark LTL_undef_regs_slot:
forall sl ofs ty rl ls, LTL.undef_regs rl ls (S sl ofs ty) = ls (S sl ofs ty).
Proof.
induction rl; simpl; intros. auto.
rewrite Locmap.gso. apply IHrl. red; auto.
Qed.
Remark undef_regs_type:
forall ty l rl ls,
Val.has_type (ls l) ty -> Val.has_type (LTL.undef_regs rl ls l) ty.
Proof.
induction rl; simpl; intros.
- auto.
- unfold Locmap.set. destruct (Loc.eq (R a) l). red; auto.
destruct (Loc.diff_dec (R a) l); auto. red; auto.
Qed.
Lemma save_callee_save_correct:
forall j ls ls0 rs sp cs fb k m P,
m |= range sp fe.(fe_ofs_callee_save) (size_callee_save_area b fe.(fe_ofs_callee_save)) ** P ->
(forall r, Val.has_type (ls (R r)) (mreg_type r)) ->
agree_callee_save ls ls0 ->
agree_regs j ls rs ->
let ls1 := LTL.undef_regs destroyed_at_function_entry (LTL.call_regs ls) in