summaryrefslogtreecommitdiff
path: root/backend/Alloctyping.v
blob: 4c4c4f762dc2b73a4cf156aa45dbd3b54771b594 (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
(** Preservation of typing during register allocation. *)

Require Import Coqlib.
Require Import Maps.
Require Import AST.
Require Import Op.
Require Import Registers.
Require Import RTL.
Require Import Locations.
Require Import LTL.
Require Import Coloring.
Require Import Coloringproof.
Require Import Allocation.
Require Import Allocproof.
Require Import RTLtyping.
Require Import LTLtyping.
Require Import Conventions.
Require Import Parallelmove.

(** This file proves that register allocation (the translation from
  RTL to LTL defined in file [Allocation]) preserves typing:
  given a well-typed RTL input, it produces LTL code that is
  well-typed. *)

Section TYPING_FUNCTION.

Variable f: RTL.function.
Variable env: regenv.
Variable live: PMap.t Regset.t.
Variable alloc: reg -> loc.
Variable tf: LTL.function.

Hypothesis TYPE_RTL: type_function f = Some env.
Hypothesis ALLOC: regalloc f live (live0 f live) env = Some alloc.
Hypothesis TRANSL: transf_function f = Some tf.

Lemma wt_rtl_function: RTLtyping.wt_function f env.
Proof.
  apply type_function_correct; auto.
Qed.

Lemma alloc_type: forall r, Loc.type (alloc r) = env r.
Proof.
  intro. eapply regalloc_preserves_types; eauto.
Qed.

Lemma alloc_types:
  forall rl, List.map Loc.type (List.map alloc rl) = List.map env rl.
Proof.
  intros. rewrite list_map_compose. apply list_map_exten.
  intros. symmetry. apply alloc_type. 
Qed.

(** [loc_read_ok l] states whether location [l] is well-formed in an
  argument context (for reading). *)

Definition loc_read_ok (l: loc) : Prop :=
  match l with R r => True | S s => slot_bounded tf s end.

(** [loc_write_ok l] states whether location [l] is well-formed in a
  result context (for writing). *)

Definition loc_write_ok (l: loc) : Prop :=
  match l with 
  | R r => True
  | S (Incoming _ _) => False
  | S s => slot_bounded tf s end.

Definition locs_read_ok (ll: list loc) : Prop :=
  forall l, In l ll -> loc_read_ok l.

Definition locs_write_ok (ll: list loc) : Prop :=
  forall l, In l ll -> loc_write_ok l.

Remark loc_write_ok_read_ok:
  forall l, loc_write_ok l -> loc_read_ok l.
Proof.
  destruct l; simpl. auto.
  destruct s; tauto.
Qed.
Hint Resolve loc_write_ok_read_ok: allocty.

Remark locs_write_ok_read_ok:
  forall ll, locs_write_ok ll -> locs_read_ok ll.
Proof.
  unfold locs_write_ok, locs_read_ok. auto with allocty.
Qed.
Hint Resolve locs_write_ok_read_ok: allocty.

Lemma alloc_write_ok:
  forall r, loc_write_ok (alloc r).
Proof.
  intros. generalize (regalloc_acceptable _ _ _ _ _ r ALLOC).
  destruct (alloc r); simpl. auto. 
  destruct s; try contradiction. simpl. omega.
Qed.
Hint Resolve alloc_write_ok: allocty.

Lemma allocs_write_ok:
  forall rl, locs_write_ok (List.map alloc rl).
Proof.
  intros; red; intros.
  generalize (list_in_map_inv _ _ _ H). intros [r [EQ IN]].
  subst l. auto with allocty.
Qed.
Hint Resolve allocs_write_ok: allocty.

(** * Typing LTL constructors *)

(** We show that the LTL constructor functions defined in [Allocation]
  generate well-typed LTL basic blocks, given sufficient typing
  and well-formedness hypotheses over the locations involved. *)

Lemma wt_add_reload:
  forall src dst k,
  loc_read_ok src ->
  Loc.type src = mreg_type dst ->
  wt_block tf k ->
  wt_block tf (add_reload src dst k).
Proof.
  intros. unfold add_reload. destruct src. 
  case (mreg_eq m dst); intro. auto. apply wt_Bopmove. exact H0. auto.
  apply wt_Bgetstack. exact H0. exact H. auto.
Qed.

Lemma wt_add_spill:
  forall src dst k,
  loc_write_ok dst ->
  mreg_type src = Loc.type dst ->
  wt_block tf k ->
  wt_block tf (add_spill src dst k).
Proof.
  intros. unfold add_spill. destruct dst. 
  case (mreg_eq src m); intro. auto. 
  apply wt_Bopmove. exact H0. auto.
  apply wt_Bsetstack. generalize H. simpl. destruct s; auto.
  symmetry. exact H0. generalize H. simpl. destruct s; auto. contradiction.
  auto.
Qed.

Lemma wt_add_reloads:
  forall srcs dsts k,
  locs_read_ok srcs ->
  List.map Loc.type srcs = List.map mreg_type dsts ->
  wt_block tf k ->
  wt_block tf (add_reloads srcs dsts k).
Proof.
  induction srcs; intros.
  destruct dsts. simpl; auto. simpl in H0; discriminate. 
  destruct dsts; simpl in H0. discriminate. simpl. 
  apply wt_add_reload. apply H; apply in_eq. congruence. 
  apply IHsrcs. red; intros; apply H; apply in_cons; auto.
  congruence. auto.
Qed.

Lemma wt_reg_for:
  forall l, mreg_type (reg_for l) = Loc.type l.
Proof.
  intros. destruct l; simpl. auto.
  case (slot_type s); reflexivity.
Qed.
Hint Resolve wt_reg_for: allocty.

Lemma wt_regs_for_rec:
  forall locs itmps ftmps,
  (List.length locs <= List.length itmps)%nat ->
  (List.length locs <= List.length ftmps)%nat ->
  (forall r, In r itmps -> mreg_type r = Tint) ->
  (forall r, In r ftmps -> mreg_type r = Tfloat) ->
  List.map mreg_type (regs_for_rec locs itmps ftmps) = List.map Loc.type locs.
Proof.
  induction locs; intros.
  simpl. auto.
  destruct itmps; simpl in H. omegaContradiction.
  destruct ftmps; simpl in H0. omegaContradiction.
  simpl. apply (f_equal2 (@cons typ)). 
  destruct a. reflexivity. simpl. case (slot_type s).
  apply H1; apply in_eq. apply H2; apply in_eq.
  apply IHlocs. omega. omega. 
  intros; apply H1; apply in_cons; auto.
  intros; apply H2; apply in_cons; auto.
Qed.

Lemma wt_regs_for:
  forall locs,
  (List.length locs <= 3)%nat ->
  List.map mreg_type (regs_for locs) = List.map Loc.type locs.
Proof.
  intros. unfold regs_for. apply wt_regs_for_rec.
  simpl. auto. simpl. auto. 
  simpl; intros; intuition; subst r; reflexivity.
  simpl; intros; intuition; subst r; reflexivity.
Qed.
Hint Resolve wt_regs_for: allocty.

Lemma wt_add_move:
  forall src dst b,
  loc_read_ok src -> loc_write_ok dst ->
  Loc.type src = Loc.type dst ->
  wt_block tf b ->
  wt_block tf (add_move src dst b).
Proof.
  intros. unfold add_move. 
  case (Loc.eq src dst); intro.
  auto.
  destruct src. apply wt_add_spill; auto. 
  destruct dst. apply wt_add_reload; auto.
  set (tmp := match slot_type s with Tint => IT1 | Tfloat => FT1 end).
  apply wt_add_reload. auto. 
  simpl. unfold tmp. case (slot_type s); reflexivity.
  apply wt_add_spill. auto.
  simpl. simpl in H1. rewrite <- H1. unfold tmp. case (slot_type s); reflexivity.
  auto.
Qed.

Lemma wt_add_moves:
  forall b moves,
  (forall s d, In (s, d) moves ->
      loc_read_ok s /\ loc_write_ok d /\ Loc.type s = Loc.type d) ->
  wt_block tf b ->
  wt_block tf 
    (List.fold_right (fun p k => add_move (fst p) (snd p) k) b moves).
Proof.
  induction moves; simpl; intros.
  auto.
  destruct a as [s d]. simpl. 
  elim (H s d). intros A [B C]. apply wt_add_move; auto. auto. 
Qed.

Theorem wt_parallel_move:
 forall srcs dsts b,
 List.map Loc.type srcs = List.map Loc.type dsts ->
 locs_read_ok srcs ->
 locs_write_ok dsts -> wt_block tf b ->  wt_block tf (parallel_move srcs dsts b).
Proof.
  intros. unfold parallel_move. apply wt_add_moves; auto.
  intros. 
  elim (parmove_prop_2 _ _ _ _ H3); intros A B.
  split. destruct A as [C|[C|C]]. 
  apply H0; auto. subst s; exact I. subst s; exact I.
  split. destruct B as [C|[C|C]]. 
  apply H1; auto. subst d; exact I. subst d; exact I.
  eapply parmove_prop_3; eauto.
Qed.
 
Lemma wt_add_op_move:
  forall src res s,
  Loc.type src = Loc.type res ->
  loc_read_ok src -> loc_write_ok res ->
  wt_block tf (add_op Omove (src :: nil) res s).
Proof.
  intros. unfold add_op. simpl. 
  apply wt_add_move. auto. auto. auto. constructor. 
Qed.

Lemma wt_add_op_undef:
  forall res s,
  loc_write_ok res ->
  wt_block tf (add_op Oundef nil res s).
Proof.
  intros. unfold add_op. simpl. 
  apply wt_Bopundef. apply wt_add_spill. auto. auto with allocty. 
  constructor.
Qed.

Lemma wt_add_op_others:
  forall op args res s,
  op <> Omove -> op <> Oundef ->
  (List.map Loc.type args, Loc.type res) = type_of_operation op ->
  locs_read_ok args ->
  loc_write_ok res ->
  wt_block tf (add_op op args res s).
Proof.
  intros. unfold add_op. 
  caseEq (is_move_operation op args). intros.
  generalize (is_move_operation_correct op args H4). tauto.
  intro. assert ((List.length args <= 3)%nat).
    replace (length args) with (length (fst (type_of_operation op))).
    apply Allocproof.length_type_of_operation. 
    rewrite <- H1. simpl. apply list_length_map. 
  generalize (wt_regs_for args H5); intro.
  generalize (wt_reg_for res); intro.
  apply wt_add_reloads. auto. auto. 
  apply wt_Bop. auto. auto. congruence. 
  apply wt_add_spill. auto. auto. constructor.
Qed.

Lemma wt_add_load:
  forall chunk addr args dst s,
  List.map Loc.type args = type_of_addressing addr ->
  Loc.type dst = type_of_chunk chunk ->
  locs_read_ok args ->
  loc_write_ok dst ->
  wt_block tf (add_load chunk addr args dst s).
Proof.
  intros. unfold add_load.
  assert ((List.length args <= 2)%nat).
    replace (length args) with (length (type_of_addressing addr)).
    apply Allocproof.length_type_of_addressing.
    rewrite <- H. apply list_length_map.
  assert ((List.length args <= 3)%nat). omega.
  generalize (wt_regs_for args H4); intro.
  generalize (wt_reg_for dst); intro.
  apply wt_add_reloads. auto. auto. 
  apply wt_Bload. congruence. congruence. 
  apply wt_add_spill. auto. auto. constructor.
Qed.

Lemma wt_add_store:
  forall chunk addr args src s,
  List.map Loc.type args = type_of_addressing addr ->
  Loc.type src = type_of_chunk chunk ->
  locs_read_ok args ->
  loc_read_ok src ->
  wt_block tf (add_store chunk addr args src s).
Proof.
  intros. unfold add_store.
  assert ((List.length args <= 2)%nat).
    replace (length args) with (length (type_of_addressing addr)).
    apply Allocproof.length_type_of_addressing.
    rewrite <- H. apply list_length_map.
  assert ((List.length (src :: args) <= 3)%nat). simpl. omega.
  generalize (wt_regs_for (src :: args) H4); intro.
  caseEq (regs_for (src :: args)).
  intro. constructor.
  intros rsrc rargs EQ. rewrite EQ in H5. simpl in H5.
  apply wt_add_reloads. 
  red; intros. elim H6; intro. subst l; auto. auto. 
  simpl. congruence. 
  apply wt_Bstore. congruence. congruence. constructor.
Qed.

Lemma wt_add_call:
  forall sig los args res s,
  match los with inl l => Loc.type l = Tint | inr s => True end ->
  List.map Loc.type args = sig.(sig_args) ->
  Loc.type res = match sig.(sig_res) with None => Tint | Some ty => ty end ->
  locs_read_ok args ->
  match los with inl l => loc_read_ok l | inr s => True end ->
  loc_write_ok res ->
  wt_block tf (add_call sig los args res s).
Proof.
  intros. 
  assert (locs_write_ok (loc_arguments sig)).
    red; intros. generalize (loc_arguments_acceptable sig l H5).
    destruct l; simpl. auto. 
    destruct s0; try contradiction. simpl. omega.
  unfold add_call. destruct los.
  apply wt_add_reload. auto. simpl; congruence. 
  apply wt_parallel_move. rewrite loc_arguments_type. auto.
  auto. auto. 
  apply wt_Bcall. reflexivity. 
  apply wt_add_spill. auto. 
  rewrite loc_result_type. auto. constructor.
  apply wt_parallel_move. rewrite loc_arguments_type. auto.
  auto. auto. 
  apply wt_Bcall. auto.
  apply wt_add_spill. auto. 
  rewrite loc_result_type. auto. constructor.
Qed.

Lemma wt_add_alloc:
  forall arg res s,
  Loc.type arg = Tint -> Loc.type res = Tint ->
  loc_read_ok arg -> loc_write_ok res ->
  wt_block tf (add_alloc arg res s).
Proof.
  intros. 
  unfold add_alloc. apply wt_add_reload. auto. rewrite H; reflexivity.
  apply wt_Balloc. apply wt_add_spill. auto. rewrite H0; reflexivity.
  apply wt_Bgoto. 
Qed.

Lemma wt_add_cond:
  forall cond args ifso ifnot,
  List.map Loc.type args = type_of_condition cond ->
  locs_read_ok args ->
  wt_block tf (add_cond cond args ifso ifnot).
Proof.
  intros. 
  assert ((List.length args) <= 3)%nat.
    replace (length args) with (length (type_of_condition cond)).
    apply Allocproof.length_type_of_condition. 
    rewrite <- H. apply list_length_map. 
  generalize (wt_regs_for args H1). intro.  
  unfold add_cond. apply wt_add_reloads.
  auto. auto. 
  apply wt_Bcond. congruence. 
Qed.

Lemma wt_add_return:
  forall sig optarg,
  option_map Loc.type optarg = sig.(sig_res) ->
  match optarg with None => True | Some arg => loc_read_ok arg end ->
  wt_block tf (add_return sig optarg).
Proof.
  intros. unfold add_return. destruct optarg.
  apply wt_add_reload. auto. rewrite loc_result_type. 
  simpl in H. destruct (sig_res sig). congruence. discriminate.
  constructor.
  apply wt_Bopundef. constructor.
Qed.

Lemma wt_add_undefs:
  forall ll b,
  wt_block tf b -> wt_block tf (add_undefs ll b).
Proof.
  induction ll; intros.
  simpl. auto. 
  simpl. destruct a. apply wt_Bopundef. auto. auto.
Qed.

Lemma wt_add_entry:
  forall params undefs s,
  List.map Loc.type params = sig_args (RTL.fn_sig f) ->
  locs_write_ok params ->
  wt_block tf (add_entry (RTL.fn_sig f) params undefs s).
Proof.
  set (sig := RTL.fn_sig f).
  assert (sig = tf.(fn_sig)).
    unfold sig. 
    assert (transf_fundef (Internal f) = Some (Internal tf)).
      unfold transf_fundef, transf_partial_fundef. rewrite TRANSL; auto.
    generalize (Allocproof.sig_function_translated _ _ H). simpl; auto.
  assert (locs_read_ok (loc_parameters sig)).
    red; unfold loc_parameters. intros. 
    generalize (list_in_map_inv _ _ _ H0). intros [l1 [EQ IN]].
    subst l. generalize (loc_arguments_acceptable _ _ IN).
    destruct l1. simpl. auto. 
    destruct s; try contradiction. 
    simpl; intros. split. omega. rewrite <- H. 
    apply loc_arguments_bounded. auto.
  intros. unfold add_entry.
  apply wt_parallel_move. rewrite loc_parameters_type. auto.
  auto. auto. 
  apply wt_add_undefs. constructor.
Qed.

(** * Type preservation during translation from RTL to LTL *)

Lemma wt_transf_instr:
  forall pc instr,
  RTLtyping.wt_instr env f.(RTL.fn_sig) instr ->
  wt_block tf (transf_instr f live alloc pc instr).
Proof.
  intros. inversion H; simpl.
  (* nop *)
  constructor.
  (* move *)
  case (Regset.mem r live!!pc). 
  apply wt_add_op_move; auto with allocty.
  repeat rewrite alloc_type. auto. constructor.
  (* undef *)
  case (Regset.mem r live!!pc). 
  apply wt_add_op_undef; auto with allocty.
  constructor.
  (* other ops *)
  case (Regset.mem res live!!pc). 
  apply wt_add_op_others; auto with allocty. 
  rewrite alloc_types. rewrite alloc_type. auto. 
  constructor.
  (* load *)
  case (Regset.mem dst live!!pc). 
  apply wt_add_load; auto with allocty. 
  rewrite alloc_types. auto. rewrite alloc_type. auto. 
  constructor.
  (* store *)
  apply wt_add_store; auto with allocty.
  rewrite alloc_types. auto. rewrite alloc_type. auto. 
  (* call *)
  apply wt_add_call. 
  destruct ros; simpl. rewrite alloc_type; auto. auto. 
  rewrite alloc_types; auto.
  rewrite alloc_type. auto. 
  auto with allocty.
  destruct ros; simpl; auto with allocty.
  auto with allocty.
  (* alloc *)
  apply wt_add_alloc; auto with allocty.
  rewrite alloc_type; auto. rewrite alloc_type; auto.
  (* cond *)
  apply wt_add_cond. rewrite alloc_types; auto. auto with allocty.
  (* return *)
  apply wt_add_return. 
  destruct optres; simpl. rewrite alloc_type. exact H0. exact H0.
  destruct optres; simpl; auto with allocty.
Qed.

Lemma wt_transf_instrs:
  let c := PTree.map (transf_instr f live alloc) (RTL.fn_code f) in
  forall pc b, c!pc = Some b -> wt_block tf b.
Proof.
  intros until b.
  unfold c. rewrite PTree.gmap. caseEq (RTL.fn_code f)!pc. 
  intros instr EQ. simpl. intros. injection H; intro; subst b.
  apply wt_transf_instr. eapply RTLtyping.wt_instrs; eauto.
  apply wt_rtl_function. 
  simpl; intros; discriminate.
Qed.

Lemma wt_transf_entrypoint:
  let c := transf_entrypoint f live alloc
            (PTree.map (transf_instr f live alloc) (RTL.fn_code f)) in
  (forall pc b, c!pc = Some b -> wt_block tf b).
Proof.
  simpl. unfold transf_entrypoint. 
  intros pc b. rewrite PTree.gsspec. 
  case (peq pc (fn_nextpc f)); intros.
  injection H; intro; subst b. 
  apply wt_add_entry.
  rewrite alloc_types. eapply RTLtyping.wt_params. apply wt_rtl_function.
  auto with allocty. 
  apply wt_transf_instrs with pc; auto.
Qed.

End TYPING_FUNCTION.

Lemma wt_transf_function:
  forall f tf,
  transf_function f = Some tf -> wt_function tf.
Proof.
  intros. generalize H; unfold transf_function.
  caseEq (type_function f). intros env TYP. 
  caseEq (analyze f). intros live ANL.
  change (transfer f (RTL.fn_entrypoint f)
                     live!!(RTL.fn_entrypoint f))
    with (live0 f live).
  caseEq (regalloc f live (live0 f live) env).
  intros alloc ALLOC.
  intro EQ; injection EQ; intro; subst tf.
  red. simpl. intros. eapply wt_transf_entrypoint; eauto.
  intros; discriminate.
  intros; discriminate.
  intros; discriminate.
Qed. 

Lemma wt_transf_fundef:
  forall f tf,
  transf_fundef f = Some tf -> wt_fundef tf.
Proof.
  intros until tf; destruct f; simpl. 
  caseEq (transf_function f). intros g TF EQ. inversion EQ.
  constructor. eapply wt_transf_function; eauto.
  congruence.
  intros. inversion H. constructor. 
Qed.

Lemma program_typing_preserved:
  forall (p: RTL.program) (tp: LTL.program),
  transf_program p = Some tp ->
  LTLtyping.wt_program tp.
Proof.
  intros; red; intros.
  generalize (transform_partial_program_function transf_fundef p i f H H0).
  intros [f0 [IN TRANSF]].
  apply wt_transf_fundef with f0; auto.
Qed.