summaryrefslogtreecommitdiff
path: root/backend/Linearizetyping.v
blob: 6cebca8d7304484b4e38218364b35bad6a5ac831 (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
(** Type preservation for the Linearize pass *)

Require Import Coqlib.
Require Import Maps.
Require Import AST.
Require Import Op.
Require Import Locations.
Require Import LTL.
Require Import Linear.
Require Import Linearize.
Require Import LTLtyping.
Require Import Lineartyping.
Require Import Conventions.

(** * Validity of resource bounds *)

(** In this section, we show that the resource bounds computed by
  [function_bounds] are valid: all references to callee-save registers
  and stack slots in the code of the function are within those bounds. *)

Section BOUNDS.

Variable f: Linear.function.
Let b := function_bounds f.

Lemma max_over_list_bound:
  forall (A: Set) (valu: A -> Z) (l: list A) (x: A),
  In x l -> valu x <= max_over_list A valu l.
Proof.
  intros until x. unfold max_over_list.
  assert (forall c z,
            let f := fold_left (fun x y => Zmax x (valu y)) c z in
            z <= f /\ (In x c -> valu x <= f)).
    induction c; simpl; intros.
    split. omega. tauto.
    elim (IHc (Zmax z (valu a))); intros. 
    split. apply Zle_trans with (Zmax z (valu a)). apply Zmax1. auto. 
    intro H1; elim H1; intro. 
    subst a. apply Zle_trans with (Zmax z (valu x)). 
    apply Zmax2. auto. auto.
  intro. elim (H l 0); intros. auto.
Qed.

Lemma max_over_instrs_bound:
  forall (valu: instruction -> Z) i,
  In i f.(fn_code) -> valu i <= max_over_instrs f valu.
Proof.
  intros. unfold max_over_instrs. apply max_over_list_bound; auto.
Qed.

Lemma max_over_regs_of_funct_bound:
  forall (valu: mreg -> Z) i r,
  In i f.(fn_code) -> In r (regs_of_instr i) ->
  valu r <= max_over_regs_of_funct f valu.
Proof.
  intros. unfold max_over_regs_of_funct. 
  apply Zle_trans with (max_over_regs_of_instr valu i).
  unfold max_over_regs_of_instr. apply max_over_list_bound. auto.
  apply max_over_instrs_bound. auto.
Qed.

Lemma max_over_slots_of_funct_bound:
  forall (valu: slot -> Z) i s,
  In i f.(fn_code) -> In s (slots_of_instr i) ->
  valu s <= max_over_slots_of_funct f valu.
Proof.
  intros. unfold max_over_slots_of_funct. 
  apply Zle_trans with (max_over_slots_of_instr valu i).
  unfold max_over_slots_of_instr. apply max_over_list_bound. auto.
  apply max_over_instrs_bound. auto.
Qed.

Lemma int_callee_save_bound:
  forall i r,
  In i f.(fn_code) -> In r (regs_of_instr i) ->
  index_int_callee_save r < bound_int_callee_save b.
Proof.
  intros. apply Zlt_le_trans with (int_callee_save r).
  unfold int_callee_save. omega.
  unfold b, function_bounds, bound_int_callee_save. 
  eapply max_over_regs_of_funct_bound; eauto.
Qed.

Lemma float_callee_save_bound:
  forall i r,
  In i f.(fn_code) -> In r (regs_of_instr i) ->
  index_float_callee_save r < bound_float_callee_save b.
Proof.
  intros. apply Zlt_le_trans with (float_callee_save r).
  unfold float_callee_save. omega.
  unfold b, function_bounds, bound_float_callee_save. 
  eapply max_over_regs_of_funct_bound; eauto.
Qed.

Lemma int_local_slot_bound:
  forall i ofs,
  In i f.(fn_code) -> In (Local ofs Tint) (slots_of_instr i) ->
  ofs < bound_int_local b.
Proof.
  intros. apply Zlt_le_trans with (int_local (Local ofs Tint)).
  unfold int_local. omega.
  unfold b, function_bounds, bound_int_local.
  eapply max_over_slots_of_funct_bound; eauto.
Qed.

Lemma float_local_slot_bound:
  forall i ofs,
  In i f.(fn_code) -> In (Local ofs Tfloat) (slots_of_instr i) ->
  ofs < bound_float_local b.
Proof.
  intros. apply Zlt_le_trans with (float_local (Local ofs Tfloat)).
  unfold float_local. omega.
  unfold b, function_bounds, bound_float_local.
  eapply max_over_slots_of_funct_bound; eauto.
Qed.

Lemma outgoing_slot_bound:
  forall i ofs ty,
  In i f.(fn_code) -> In (Outgoing ofs ty) (slots_of_instr i) ->
  ofs + typesize ty <= bound_outgoing b.
Proof.
  intros. change (ofs + typesize ty) with (outgoing_slot (Outgoing ofs ty)).
  unfold b, function_bounds, bound_outgoing.
  apply Zmax_bound_r. apply Zmax_bound_r. 
  eapply max_over_slots_of_funct_bound; eauto.
Qed.

Lemma size_arguments_bound:
  forall sig ros,
  In (Lcall sig ros) f.(fn_code) ->
  size_arguments sig <= bound_outgoing b.
Proof.
  intros. change (size_arguments sig) with (outgoing_space (Lcall sig ros)).
  unfold b, function_bounds, bound_outgoing.
  apply Zmax_bound_r. apply Zmax_bound_l.
  apply max_over_instrs_bound; auto.
Qed.

End BOUNDS.

(** Consequently, all machine registers or stack slots mentioned by one
  of the instructions of function [f] are within bounds. *)

Lemma mreg_is_bounded:
  forall f i r,
  In i f.(fn_code) -> In r (regs_of_instr i) ->
  mreg_bounded f r.
Proof.
  intros. unfold mreg_bounded. 
  case (mreg_type r).
  eapply int_callee_save_bound; eauto.
  eapply float_callee_save_bound; eauto.
Qed.

Lemma slot_is_bounded:
  forall f i s,
  In i (transf_function f).(fn_code) -> In s (slots_of_instr i) ->
  LTLtyping.slot_bounded f s ->
  slot_bounded (transf_function f) s.
Proof.
  intros. unfold slot_bounded. 
  destruct s.
  destruct t.
  split. exact H1. eapply int_local_slot_bound; eauto.
  split. exact H1. eapply float_local_slot_bound; eauto.
  unfold linearize_function; simpl. exact H1.
  split. exact H1. eapply outgoing_slot_bound; eauto.
Qed.

(** * Conservation property of the cleanup pass *)

(** We show that the cleanup pass only deletes some [Lgoto] instructions:
  all other instructions present in the output of naive linearization
  are in the cleaned-up code, and all instructions in the cleaned-up code
  are in the output of naive linearization. *)

Lemma cleanup_code_conservation:
  forall i,
  match i with Lgoto _ => False | _ => True end ->
  forall c,
  In i c -> In i (cleanup_code c).
Proof.
  induction c; simpl.
  auto.
  intro.
  assert (In i (a :: cleanup_code c)).
    elim H0; intro. subst i. auto with coqlib.
    apply in_cons. auto.
  destruct a; auto. 
  assert (In i (cleanup_code c)).
    elim H1; intro. subst i. contradiction. auto.
  case (starts_with l c). auto. apply in_cons; auto. 
Qed.

Lemma cleanup_function_conservation:
  forall f i,
  In i (linearize_function f).(fn_code) ->
  match i with Lgoto _ => False | _ => True end ->
  In i (transf_function f).(fn_code).
Proof.
  intros. unfold transf_function. unfold cleanup_function.
  simpl. simpl in H0. eapply cleanup_code_conservation; eauto.
Qed.

Lemma cleanup_code_conservation_2:
  forall i c, In i (cleanup_code c) -> In i c.
Proof.
  induction c; simpl.
  auto.
  assert (In i (a :: cleanup_code c) -> a = i \/ In i c).
    intro. elim H; tauto.
  destruct a; auto.
  case (starts_with l c). auto. auto. 
Qed.

Lemma cleanup_function_conservation_2:
  forall f i,
  In i (transf_function f).(fn_code) ->
  In i (linearize_function f).(fn_code).
Proof.
  simpl. intros. eapply cleanup_code_conservation_2; eauto.
Qed.

(** * Type preservation for the linearization pass *)

Lemma linearize_block_incl:
  forall k b, incl k (linearize_block b k).
Proof.
  induction b; simpl; auto with coqlib.
  case (starts_with n k); auto with coqlib.
Qed.

Lemma wt_linearize_block:
  forall f k,
  (forall i, In i k -> wt_instr (transf_function f) i) ->
  forall b i,
  wt_block f b ->
  incl (linearize_block b k) (linearize_function f).(fn_code) ->
  In i (linearize_block b k) -> wt_instr (transf_function f) i.
Proof.
  induction b; simpl; intros;
  try (generalize (cleanup_function_conservation 
                     _ _ (H1 _ (in_eq _ _)) I));
  inversion H0;
  try (elim H2; intro; [subst i|eauto with coqlib]);
  intros.
  (* getstack *)
  constructor. auto. eapply slot_is_bounded; eauto.
  simpl; auto with coqlib. 
  eapply mreg_is_bounded; eauto.
  simpl; auto with coqlib. 
  (* setstack *)
  constructor. auto. auto. 
  eapply slot_is_bounded; eauto. 
  simpl; auto with coqlib. 
  (* move *)
  subst o; subst l. constructor. auto. 
  eapply mreg_is_bounded; eauto.
  simpl; auto with coqlib. 
  (* undef *)
  subst o; subst l. constructor. 
  eapply mreg_is_bounded; eauto.
  simpl; auto with coqlib. 
  (* other ops *)
  constructor; auto. 
  eapply mreg_is_bounded; eauto.
  simpl; auto with coqlib. 
  (* load *)
  constructor; auto.
  eapply mreg_is_bounded; eauto.
  simpl; auto with coqlib. 
  (* store *)
  constructor; auto.
  (* call *)
  constructor; auto. 
  eapply size_arguments_bound; eauto.
  (* goto *)
  constructor. 
  (* cond *)
  destruct (starts_with n k).
  elim H2; intro.
  subst i. constructor. 
  rewrite H4. destruct c; reflexivity.
  elim H8; intro.
  subst i. constructor.
  eauto with coqlib.
  elim H2; intro.
  subst i. constructor. auto.
  elim H8; intro.
  subst i. constructor.
  eauto with coqlib.
  (* return *)
  constructor.
Qed.

Lemma wt_linearize_body:
  forall f,
  LTLtyping.wt_function f ->
  forall enum i,
  incl (linearize_body f enum) (linearize_function f).(fn_code) ->
  In i (linearize_body f enum) -> wt_instr (transf_function f) i.
Proof.
  induction enum.
  simpl; intros; contradiction.
  intro i. simpl.
  caseEq (LTL.fn_code f)!a. intros b EQ INCL IN.
  elim IN; intro. subst i; constructor. 
  apply wt_linearize_block with (linearize_body f enum) b.
  intros; apply IHenum. 
  apply incl_tran with (linearize_block b (linearize_body f enum)).
  apply linearize_block_incl.
  eauto with coqlib.
  auto.
  eapply H; eauto.
  eauto with coqlib. auto.
  auto.
Qed. 

Lemma wt_transf_function:
  forall f,
  LTLtyping.wt_function f ->
  wt_function (transf_function f). 
Proof.
  intros; red; intros.
  apply wt_linearize_body with (enumerate f); auto.
  simpl. apply incl_refl.
  apply cleanup_function_conservation_2; auto.
Qed.

Lemma program_typing_preserved:
  forall (p: LTL.program),
  LTLtyping.wt_program p ->
  Lineartyping.wt_program (transf_program p).
Proof.
  intros; red; intros.
  generalize (transform_program_function transf_function p i f H0).
  intros [f0 [IN TR]].
  subst f. apply wt_transf_function; auto. 
  apply (H i f0 IN).
Qed.