aboutsummaryrefslogtreecommitdiffstats
path: root/mppa_k1c/Machblockgen.v
blob: 039e6c6ef9e809de6fae79cbfa9edf1676311ad7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
Require Import Coqlib.
Require Import Maps.
Require Import AST.
Require Import Integers.
Require Import Values.
Require Import Memory.
Require Import Globalenvs.
Require Import Events.
Require Import Smallstep.
Require Import Op.
Require Import Locations.
Require Import Conventions.
Require Stacklayout.
Require Import Mach.
Require Import Linking.
Require Import Machblock.

Definition to_basic_inst(i: Mach.instruction): option basic_inst :=
  match i with
  | Mgetstack ofs ty dst          => Some (MBgetstack ofs ty dst)
  | Msetstack src ofs ty          => Some (MBsetstack src ofs ty)
  | Mgetparam ofs ty dst          => Some (MBgetparam ofs ty dst)
  | Mop       op args res         => Some (MBop       op args res)
  | Mload     chunk addr args dst => Some (MBload     chunk addr args dst)
  | Mstore    chunk addr args src => Some (MBstore    chunk addr args src)
  | _ => None
  end.

Fixpoint to_bblock_body(c: Mach.code): bblock_body * Mach.code :=
  match c with
  | nil => (nil,nil)
  | i::c' =>
    match to_basic_inst i with
    | Some bi =>
       let (p,c'') := to_bblock_body c' in
       (bi::p, c'')
    | None => (nil, c)
    end
  end.

Definition to_bblock_header (c: Mach.code): option label * Mach.code :=
  match c with
  | (Mlabel l)::c' => (Some l, c')
  | _ => (None, c)
  end.


Definition to_cfi (i: Mach.instruction): option control_flow_inst :=
  match i with
  | Mcall sig ros         => Some (MBcall sig ros)
  | Mtailcall sig ros     => Some (MBtailcall sig ros)
  | Mbuiltin ef args res  => Some (MBbuiltin ef args res)
  | Mgoto lbl             => Some (MBgoto lbl)
  | Mcond cond args lbl   => Some (MBcond cond args lbl)
  | Mjumptable arg tbl    => Some (MBjumptable arg tbl)
  | Mreturn               => Some (MBreturn)
  | _ => None
  end.

Definition to_bblock_exit (c: Mach.code): option control_flow_inst * Mach.code :=
  match c with
  | nil => (None,nil)
  | i::c' =>
    match to_cfi i with
    | Some bi as o => (o, c')
    | None => (None, c)
    end
  end.

Inductive code_nature: Set := IsEmpty | IsLabel | IsBasicInst | IsCFI.

Definition get_code_nature (c: Mach.code): code_nature :=
  match c with
  | nil => IsEmpty
  | (Mlabel _)::_ => IsLabel
  | i::_ => match to_basic_inst i with
         | Some _ => IsBasicInst
         | None => IsCFI
         end
  end.

Lemma cn_eqdec (cn1 cn2: code_nature): { cn1=cn2 } + {cn1 <> cn2}.
Proof.
  decide equality.
Qed.

Lemma get_code_nature_nil c: c<>nil -> get_code_nature c <> IsEmpty.
Proof.
  intros H. unfold get_code_nature.
  destruct c; try (contradict H; auto; fail).
  destruct i; discriminate.
Qed.

Lemma get_code_nature_nil_contra c: get_code_nature c = IsEmpty -> c = nil.
Proof.
  intros H. destruct c; auto. exploit (get_code_nature_nil (i::c)); discriminate || auto.
  intro F. contradict F.
Qed.

Lemma get_code_nature_basic_inst c a c0:
  c = a :: c0 ->
  get_code_nature c = IsBasicInst ->
  to_basic_inst a <> None.
Proof.
  intros H1 H2. destruct a; discriminate || contradict H2; subst; simpl; discriminate.
Qed.

Lemma to_bblock_header_not_IsLabel c b c0:
  get_code_nature c <> IsLabel ->
  to_bblock_header c = (b, c0) ->
  c = c0 /\ b=None.
Proof.
  intros H1 H2. destruct c.
  - simpl in H2; inversion H2; auto.
  - destruct i; unfold to_bblock_header in H2; inversion H2; auto.
    simpl in H1; contradict H1; auto.
Qed.

Lemma to_bblock_header_eq c b c0:
  get_code_nature c <> IsLabel ->
  to_bblock_header c = (b, c0) ->
  c = c0.
Proof.
  intros H1 H2; exploit to_bblock_header_not_IsLabel; intuition eauto.
Qed.

Lemma to_bblock_header_IsLabel c c0 b:
  get_code_nature c = IsLabel ->
  to_bblock_header c = (b, c0) ->
  exists l, c = (Mlabel l)::c0.
Proof.
  intros H1 H2. destruct c; try discriminate.
  destruct i; try discriminate.
  unfold to_bblock_header in H2; inversion H2; eauto.
Qed.

Lemma to_bblock_header_wf c b c0:
  get_code_nature c = IsLabel ->
  to_bblock_header c = (b, c0) ->
  (length c > length c0)%nat.
Proof.
  intros H1 H2; exploit to_bblock_header_IsLabel; eauto.
  intros [l X]; subst; simpl; auto.
Qed.

Lemma to_bblock_header_wfe c b c0:
  to_bblock_header c = (b, c0) ->
  (length c >= length c0)%nat.
Proof.
  destruct (cn_eqdec (get_code_nature c) IsLabel).
  - intros; exploit to_bblock_header_wf; eauto; omega.
  - intros; exploit to_bblock_header_eq; eauto. intros; subst; auto.
Qed.

Lemma to_bblock_body_eq c b c0:
  get_code_nature c <> IsBasicInst ->
  to_bblock_body c = (b, c0) ->
  c = c0.
Proof.
  intros H1 H2. destruct c.
  - simpl in H2. inversion H2. auto.
  - destruct i; try ( simpl in *; destruct H1; auto; fail ).
    all: simpl in *; inversion H2; subst; clear H2; auto.
Qed.

Lemma to_bblock_body_wfe c b c0:
  to_bblock_body c = (b, c0) ->
  (length c >= length c0)%nat.
Proof.
  generalize b c0; clear b c0.
  induction c as [|i c].
  - intros b c0 H. simpl in H. inversion H; subst; auto.
  - intros b c0 H. simpl in H. destruct (to_basic_inst i).
    + remember (to_bblock_body c) as tbbc; destruct tbbc as [p c''].
      exploit (IHc p c''); auto. inversion H; subst; simpl; omega.
    + inversion H; subst; auto.
Qed.

Inductive cons_to_bblock_body c0: Mach.code -> bblock_body -> Prop :=
  Cons_to_bbloc_body i bi c' b':
    to_basic_inst i = Some bi
    -> to_bblock_body c' = (b', c0)
    -> cons_to_bblock_body c0 (i::c') (bi::b').

Lemma to_bblock_body_IsBasicInst c b c0:
  get_code_nature c = IsBasicInst ->
  to_bblock_body c = (b, c0) ->
  cons_to_bblock_body c0 c b.
Proof.
  intros H1 H2. destruct c; [ contradict H1; simpl; discriminate | ].
  remember (to_basic_inst i) as tbii. destruct tbii.
  - simpl in H2. rewrite <- Heqtbii in H2.
    remember (to_bblock_body c) as tbbc. destruct tbbc as [p1 c1].
    inversion H2. subst. eapply Cons_to_bbloc_body; eauto.
  - destruct i; try discriminate.
Qed.

Lemma to_bblock_body_wf c b c0:
  get_code_nature c = IsBasicInst ->
  to_bblock_body c = (b, c0) ->
  (length c > length c0)%nat.
Proof.
  intros H1 H2; exploit to_bblock_body_IsBasicInst; eauto.
  intros X; destruct X.
  exploit to_bblock_body_wfe; eauto.
  simpl; omega.
Qed.

Lemma to_bblock_exit_eq c b c0:
  get_code_nature c <> IsCFI ->
  to_bblock_exit c = (b, c0) ->
  c = c0.
Proof.
  intros H1 H2. destruct c as [|i c].
  - simpl in H2; inversion H2; auto.
  - destruct i; unfold to_bblock_header in H2; inversion H2; auto;
    simpl in H1; contradict H1; auto.
Qed.

Lemma to_bblock_exit_wf c b c0:
  get_code_nature c = IsCFI ->
  to_bblock_exit c = (b, c0) ->
  (length c > length c0)%nat.
Proof.
  intros H1 H2. destruct c as [|i c]; try discriminate.
  destruct i; try discriminate;
  unfold to_bblock_header in H2; inversion H2; auto.
Qed.

Lemma to_bblock_exit_wfe c b c0:
  to_bblock_exit c = (b, c0) ->
  (length c >= length c0)%nat.
Proof.
  intros H. destruct c as [|i c].
  - simpl in H. inversion H; subst; clear H; auto.
  - destruct i; try ( simpl in H; inversion H; subst; clear H; auto ).
    all: simpl; auto.
Qed.

Definition to_bblock(c: Mach.code): bblock * Mach.code :=
  let (h,c0) := to_bblock_header c in
  let (bdy, c1) := to_bblock_body c0 in
  let (ext, c2) := to_bblock_exit c1 in
  ({| header := h; body := bdy; exit := ext |}, c2)
  .

Lemma to_bblock_double_label c l:
  get_code_nature c = IsLabel ->
  to_bblock (Mlabel l :: c) = ({| header := Some l; body := nil; exit := None |}, c).
Proof.
  intros H.
  destruct c as [|i c]; try (contradict H; simpl; discriminate).
  destruct i; try (contradict H; simpl; discriminate).
  auto.
Qed.

Lemma to_bblock_basic_inst_then_label i c bi:
  get_code_nature (i::c) = IsBasicInst ->
  get_code_nature c = IsLabel ->
  to_basic_inst i = Some bi ->
  fst (to_bblock (i::c)) = {| header := None; body := bi::nil; exit := None |}.
Proof.
  intros H1 H2 H3.
  destruct c as [|i' c]; try (contradict H1; simpl; discriminate).
  destruct i'; try (contradict H1; simpl; discriminate).
  destruct i; simpl in *; inversion H3; subst; auto.
Qed.

Lemma to_bblock_cf_inst_then_label i c cfi:
  get_code_nature (i::c) = IsCFI ->
  get_code_nature c = IsLabel ->
  to_cfi i = Some cfi ->
  fst (to_bblock (i::c)) = {| header := None; body := nil; exit := Some cfi |}.
Proof.
  intros H1 H2 H3.
  destruct c as [|i' c]; try (contradict H1; simpl; discriminate).
  destruct i'; try (contradict H1; simpl; discriminate).
  destruct i; simpl in *; inversion H3; subst; auto.
Qed.

Lemma to_bblock_single_label c l:
  get_code_nature c <> IsLabel ->
  fst (to_bblock (Mlabel l :: c)) = {|
    header := Some l;
    body := body (fst (to_bblock c));
    exit := exit (fst (to_bblock c))
  |}.
Proof.
  intros H.
  destruct c as [|i c]; simpl; auto.
  apply bblock_eq; simpl.
(* header *)
  + destruct i; try (
      remember (to_bblock _) as bb;
      unfold to_bblock in *;
      remember (to_bblock_header _) as tbh;
      destruct tbh;
      destruct (to_bblock_body _);
      destruct (to_bblock_exit _);
      subst; simpl; inversion Heqtbh; auto; fail
      ).
(* body *)
  + remember i as i0; destruct i0; try (
      remember (to_bblock _) as bb;
      unfold to_bblock in *;
      remember (to_bblock_header _) as tbh; rewrite Heqi0;
      remember (to_bblock_header (i :: _)) as tbh'; rewrite <- Heqi0 in *;
      destruct tbh; destruct tbh';
      inversion Heqtbh; inversion Heqtbh'; subst;
      destruct (to_bblock_body _);
      destruct (to_bblock_exit _); auto; fail
      ). contradict H; simpl; auto.
(* exit (same proof as body) *)
  + remember i as i0; destruct i0; try (
      remember (to_bblock _) as bb;
      unfold to_bblock in *;
      remember (to_bblock_header _) as tbh; rewrite Heqi0;
      remember (to_bblock_header (i :: _)) as tbh'; rewrite <- Heqi0 in *;
      destruct tbh; destruct tbh';
      inversion Heqtbh; inversion Heqtbh'; subst;
      destruct (to_bblock_body _);
      destruct (to_bblock_exit _); auto; fail
      ). contradict H; simpl; auto.
Qed.

Lemma to_bblock_no_label c:
  get_code_nature c <> IsLabel ->
  fst (to_bblock c) = {|
    header := None;
    body := body (fst (to_bblock c));
    exit := exit (fst (to_bblock c))
  |}.
Proof.
  intros H.
  destruct c as [|i c]; simpl; auto.
  apply bblock_eq; simpl;
  destruct i; (
      try (
        remember (to_bblock _) as bb;
        unfold to_bblock in *;
        remember (to_bblock_header _) as tbh;
        destruct tbh;
        destruct (to_bblock_body _);
        destruct (to_bblock_exit _);
        subst; simpl; inversion Heqtbh; auto; fail
      )
    || contradict H; simpl; auto ).
Qed.

Lemma to_bblock_body_nil c c':
  to_bblock_body c = (nil, c') ->
  c = c'.
Proof.
  intros H.
  destruct c as [|i c]; [ simpl in *; inversion H; auto |].
  destruct i; try ( simpl in *; remember (to_bblock_body c) as tbc; destruct tbc as [p c'']; inversion H ).
  all: auto.
Qed.

Lemma to_bblock_exit_nil c c':
  to_bblock_exit c = (None, c') ->
  c = c'.
Proof.
  intros H.
  destruct c as [|i c]; [ simpl in *; inversion H; auto |].
  destruct i; try ( simpl in *; remember (to_bblock_exit c) as tbe; destruct tbe as [p c'']; inversion H ).
  all: auto.
Qed.

Lemma to_bblock_label b l c c':
  to_bblock (Mlabel l :: c) = (b, c') ->
  exists bdy c1, to_bblock_body c = (bdy, c1) /\
  header b = Some l /\ body b = bdy /\ exit b = fst (to_bblock_exit c1).
Proof.
  intros H.
  unfold to_bblock in H; simpl in H.
  remember (to_bblock_body c) as tbbc; destruct tbbc as [bdy' c1'].
  remember (to_bblock_exit c1') as tbbe; destruct tbbe as [ext c2].
  esplit; eauto. esplit; eauto. esplit; eauto.
  inversion H; subst; clear H. simpl.
  apply (f_equal fst) in Heqtbbe. simpl in Heqtbbe. auto.
Qed.

Lemma to_bblock_label_then_nil b l c c':
  to_bblock (Mlabel l :: c) = (b, c') ->
  body b = nil ->
  exit b = None ->
  c = c'.
Proof.
  intros TOB BB EB.
  unfold to_bblock in TOB.
  remember (to_bblock_header _) as tbh; destruct tbh as [h c0].
  remember (to_bblock_body _) as tbb; destruct tbb as [bdy c1].
  remember (to_bblock_exit _) as tbe; destruct tbe as [ext c2].
  inversion TOB; subst. simpl in *. clear TOB.
  inversion Heqtbh; subst. clear Heqtbh.
  exploit to_bblock_body_nil; eauto. intros; subst. clear Heqtbb.
  exploit to_bblock_exit_nil; eauto.
Qed.

Lemma to_bblock_basic_inst c i bi:
  get_code_nature (i::c) = IsBasicInst ->
  to_basic_inst i = Some bi ->
  get_code_nature c <> IsLabel ->
  fst (to_bblock (i::c)) = {|
    header := None;
    body := bi :: body (fst (to_bblock c));
    exit := exit (fst (to_bblock c))
  |}.
Proof.
  intros.
  destruct c; try (destruct i; inversion H0; subst; simpl; auto; fail).
  apply bblock_eq; simpl.
(* header *)
  + destruct i; simpl; auto; (
      exploit to_bblock_no_label; [rewrite H; discriminate | intro; rewrite H2; simpl; auto]).
(* body *)
(* FIXME - the proof takes some time to prove.. N² complexity :( *)
  + destruct i; inversion H0; try (
      destruct i0; try (
        subst; unfold to_bblock;
        remember (to_bblock_header _) as tbh; destruct tbh;
        remember (to_bblock_header (_::c)) as tbh'; destruct tbh';
        inversion Heqtbh; inversion Heqtbh'; subst;

        remember (to_bblock_body _) as tbb; destruct tbb;
        remember (to_bblock_body (_::c)) as tbb'; destruct tbb';
        inversion Heqtbb; inversion Heqtbb'; destruct (to_bblock_body c);
        inversion H3; inversion H4; subst;

        remember (to_bblock_exit _) as tbc; destruct tbc;
        simpl; auto );
      contradict H1; simpl; auto ).
(* exit - same as body *)
  + destruct i; inversion H0; try (
      destruct i0; try (
        subst; unfold to_bblock;
        remember (to_bblock_header _) as tbh; destruct tbh;
        remember (to_bblock_header (_::c)) as tbh'; destruct tbh';
        inversion Heqtbh; inversion Heqtbh'; subst;

        remember (to_bblock_body _) as tbb; destruct tbb;
        remember (to_bblock_body (_::c)) as tbb'; destruct tbb';
        inversion Heqtbb; inversion Heqtbb'; destruct (to_bblock_body c);
        inversion H3; inversion H4; subst;

        remember (to_bblock_exit _) as tbc; destruct tbc;
        simpl; auto );
      contradict H1; simpl; auto ).
Qed.

Lemma to_bblock_size_single_label c i:
  get_code_nature (i::c) = IsLabel ->
  get_code_nature c <> IsLabel ->
  size (fst (to_bblock (i::c))) = Datatypes.S (size (fst (to_bblock c))).
Proof.
  intros.
  destruct i; try (contradict H; simpl; discriminate).
  destruct c; simpl; auto.
  destruct i; try (
    exploit to_bblock_single_label; eauto; intro; rewrite H1;
    exploit to_bblock_no_label; eauto; intro; rewrite H2;
    simpl; auto; fail ).
  Unshelve. all: auto.
Qed.

Lemma to_bblock_size_label_neqz c:
  get_code_nature c = IsLabel ->
  size (fst (to_bblock c)) <> 0%nat.
Proof.
  intros H. destruct c as [|i c]; try (contradict H; auto; simpl; discriminate).
  destruct i; try (contradict H; simpl; discriminate).
  destruct (get_code_nature c) eqn:gcnc.
  (* Case gcnc is not IsLabel *)
  all: try (rewrite to_bblock_size_single_label; auto; rewrite gcnc; discriminate).
  (* Case gcnc is IsLabel *)
  rewrite to_bblock_double_label; auto; unfold size; simpl; auto.
Qed.

Lemma to_bblock_size_basicinst_neqz c:
  get_code_nature c = IsBasicInst ->
  size (fst (to_bblock c)) <> 0%nat.
Proof.
  intros H. destruct c as [|i c]; try (contradict H; auto; simpl; discriminate).
  destruct i; try (contradict H; simpl; discriminate);
  (
    destruct (get_code_nature c) eqn:gcnc;
    (* Case gcnc is not IsLabel *)
    try (erewrite to_bblock_basic_inst; eauto; [
        unfold size; simpl; auto
      | simpl; auto
      | rewrite gcnc; discriminate
    ]);
    erewrite to_bblock_basic_inst_then_label; eauto; [
        unfold size; simpl; auto
      | simpl; auto
    ]
  ).
Qed.

Lemma to_bblock_size_cfi_neqz c:
  get_code_nature c = IsCFI ->
  size (fst (to_bblock c)) <> 0%nat.
Proof.
  intros H. destruct c as [|i c]; try (contradict H; auto; simpl; discriminate).
  destruct i; discriminate.
Qed.

Lemma to_bblock_size_single_basicinst c i:
  get_code_nature (i::c) = IsBasicInst ->
  get_code_nature c <> IsLabel ->
  size (fst (to_bblock (i::c))) = Datatypes.S (size (fst (to_bblock c))).
Proof.
  intros.
  destruct i; try (contradict H; simpl; discriminate); try (
    (exploit to_bblock_basic_inst; eauto);
      [remember (to_basic_inst _) as tbi; destruct tbi; eauto |];
    intro; rewrite H1; unfold size; simpl;
    assert ((length_opt (header (fst (to_bblock c)))) = 0%nat);
      exploit to_bblock_no_label; eauto; intro; rewrite H2; simpl; auto;
    rewrite H2; auto
  ).
Qed.

Lemma to_bblock_wf c b c0:
  c <> nil ->
  to_bblock c = (b, c0) ->
  (length c > length c0)%nat.
Proof.
  intro H; lapply (get_code_nature_nil c); eauto.
  intro H'; remember (get_code_nature c) as gcn.
  unfold to_bblock.
  remember (to_bblock_header c) as p1; eauto.
  destruct p1 as [h c1].
  intro H0.
  destruct gcn.
  - contradict H'; auto.
  - exploit to_bblock_header_wf; eauto.
    remember (to_bblock_body c1) as p2; eauto.
    destruct p2 as [h2 c2].
    exploit to_bblock_body_wfe; eauto.
    remember (to_bblock_exit c2) as p3; eauto.
    destruct p3 as [h3 c3].
    exploit to_bblock_exit_wfe; eauto.
    inversion H0. omega.
  - exploit to_bblock_header_eq; eauto. rewrite <- Heqgcn. discriminate.
    intro; subst.
    remember (to_bblock_body c1) as p2; eauto.
    destruct p2 as [h2 c2].
    exploit to_bblock_body_wf; eauto.
    remember (to_bblock_exit c2) as p3; eauto.
    destruct p3 as [h3 c3].
    exploit to_bblock_exit_wfe; eauto.
    inversion H0. omega.
  - exploit to_bblock_header_eq; eauto. rewrite <- Heqgcn. discriminate.
    intro; subst.
    remember (to_bblock_body c1) as p2; eauto.
    destruct p2 as [h2 c2].
    exploit (to_bblock_body_eq c1 h2 c2); eauto. rewrite <- Heqgcn. discriminate.
    intro; subst.
    remember (to_bblock_exit c2) as p3; eauto.
    destruct p3 as [h3 c3].
    exploit (to_bblock_exit_wf c2 h3 c3); eauto.
    inversion H0. omega.
Qed.

Lemma to_bblock_nonil c i c0:
  c = i :: c0 ->
  size (fst (to_bblock c)) <> 0%nat.
Proof.
  intros H. remember (get_code_nature c) as gcnc. destruct gcnc.
  - contradict Heqgcnc. subst. simpl. destruct i; discriminate.
  - eapply to_bblock_size_label_neqz; auto.
  - eapply to_bblock_size_basicinst_neqz; auto.
  - eapply to_bblock_size_cfi_neqz; auto.
Qed.

Lemma to_bblock_islabel c l:
  is_label l (fst (to_bblock (Mlabel l :: c))) = true.
Proof.
  unfold to_bblock.
  remember (to_bblock_header _) as tbh; destruct tbh as [h c0].
  remember (to_bblock_body _) as tbc; destruct tbc as [bdy c1].
  remember (to_bblock_exit _) as tbe; destruct tbe as [ext c2].
  simpl. inversion Heqtbh. unfold is_label. simpl.
  apply peq_true.
Qed.

Lemma body_fst_to_bblock_label l c:
  body (fst (to_bblock (Mlabel l :: c))) = fst (to_bblock_body c).
Proof.
  destruct c as [|i c']; simpl; auto.
  destruct i; simpl; auto.
  all: (
    remember (to_bblock_body c') as tbbc; destruct tbbc as [tc c'']; simpl;
    unfold to_bblock;
    remember (to_bblock_header _) as tbh; destruct tbh as [h c0];
    remember (to_bblock_body c0) as tbc; destruct tbc as [bdy c1];
    remember (to_bblock_exit c1) as tbe; destruct tbe as [ext c2];
    simpl; simpl in Heqtbh; inversion Heqtbh; subst c0;
    simpl in Heqtbc; remember (to_bblock_body c') as tbc'; destruct tbc' as [tc' osef];
    inversion Heqtbc; inversion Heqtbbc; auto
  ).
Qed.

Lemma exit_fst_to_bblock_label c c' l:
  snd (to_bblock_body c) = c' ->
  exit (fst (to_bblock (Mlabel l :: c))) = fst (to_bblock_exit c').
Proof.
  intros H. destruct c as [|i c]; [simpl in *; subst; auto |].
  unfold to_bblock.
  remember (to_bblock_header _) as tbh; destruct tbh as [h c0].
  remember (to_bblock_body c0) as tbc; destruct tbc as [bdy c1].
  remember (to_bblock_exit c1) as tbe; destruct tbe as [ext c2].
  simpl in *. inversion Heqtbh; subst.
  destruct (to_basic_inst i) eqn:TBI.
  - remember (to_bblock_body c) as tbbc; destruct tbbc as [p c''].
    simpl. simpl in Heqtbc. rewrite TBI in Heqtbc. rewrite <- Heqtbbc in Heqtbc.
    inversion Heqtbc; subst. apply (f_equal fst) in Heqtbe; auto.
  - simpl. simpl in Heqtbc. rewrite TBI in Heqtbc.
    inversion Heqtbc; subst. clear Heqtbh Heqtbc. unfold to_bblock_exit in Heqtbe.
    apply (f_equal fst) in Heqtbe; auto.
Qed.

Function trans_code (c: Mach.code) { measure length c }: code :=
  match c with
  | nil => nil
  | _ =>
     let (b, c0) := to_bblock c in
     b::(trans_code c0)
  end.
Proof.
  intros; eapply to_bblock_wf; eauto. discriminate.
Qed.

Definition hd_code (bc: code) := (hd {| header := None; body := nil; exit := None |} bc).

Lemma trans_code_nonil c:
  c <> nil -> trans_code c <> nil.
Proof.
  intros H.
  induction c, (trans_code c) using trans_code_ind; simpl; auto. discriminate.
Qed.

Lemma trans_code_step c b lb0 hb c1 bb c2 eb c3:
  trans_code c = b :: lb0 ->
  to_bblock_header c = (hb, c1) ->
  to_bblock_body c1 = (bb, c2) ->
  to_bblock_exit c2 = (eb, c3) ->
  hb = header b /\ bb = body b /\ eb = exit b /\ trans_code c3 = lb0.
Proof.
  intros.
  induction c, (trans_code c) using trans_code_ind. discriminate. clear IHc0.
  subst. destruct _x as [|i c]; try (contradict y; auto; fail).
  inversion H; subst. clear H. unfold to_bblock in e0.
  remember (to_bblock_header (i::c)) as hd. destruct hd as [hb' c1'].
  remember (to_bblock_body c1') as bd. destruct bd as [bb' c2'].
  remember (to_bblock_exit c2') as be. destruct be as [eb' c3'].
  inversion e0. simpl.
  inversion H0. subst.
  rewrite <- Heqbd in H1. inversion H1. subst.
  rewrite <- Heqbe in H2. inversion H2. subst.
  auto.
Qed.

Lemma trans_code_cfi i c cfi:
  to_cfi i = Some cfi ->
  trans_code (i :: c) = {| header := None ; body := nil ; exit := Some cfi |} :: trans_code c.
Proof.
  intros. rewrite trans_code_equation. remember (to_bblock _) as tb; destruct tb as [b c0].
  destruct i; try (contradict H; discriminate).
  all: unfold to_bblock in Heqtb; remember (to_bblock_header _) as tbh; destruct tbh as [h c0'];
      remember (to_bblock_body c0') as tbb; destruct tbb as [bdy c1'];
      remember (to_bblock_exit c1') as tbe; destruct tbe as [ext c2]; simpl in *;
      inversion Heqtbh; subst; inversion Heqtbb; subst; inversion Heqtbe; subst;
      inversion Heqtb; subst; rewrite H; auto.
Qed.

(* à finir pour passer des Mach.function au function, etc. *)
Definition trans_function (f: Mach.function) : function :=
  {| fn_sig:=Mach.fn_sig f;
     fn_code:=trans_code (Mach.fn_code f);
     fn_stacksize := Mach.fn_stacksize f;
     fn_link_ofs := Mach.fn_link_ofs f;
     fn_retaddr_ofs := Mach.fn_retaddr_ofs f
 |}.

Definition trans_fundef (f: Mach.fundef) : fundef :=
  transf_fundef trans_function f.

Definition trans_prog (src: Mach.program) : program :=
  transform_program trans_fundef src.