include "utilities/lists.ma". include "common/Globalenvs.ma". include "Cminor/syntax.ma". include "RTLabs/syntax.ma". include "utilities/pair.ma". include "utilities/deppair.ma". definition env ≝ identifier_map SymbolTag register. definition label_env ≝ identifier_map Label label. definition populate_env : env → universe RegisterTag → list (ident × typ) → list (register×typ) × env × (universe RegisterTag) ≝ λen,gen. foldr ?? (λidt,rsengen. let 〈id,ty〉 ≝ idt in let 〈rs,en,gen〉 ≝ rsengen in let 〈r,gen'〉 ≝ fresh … gen in 〈〈r,ty〉::rs, add ?? en id r, gen'〉) 〈[ ], en, gen〉. lemma populates_env : ∀l,e,u,l',e',u'. populate_env e u l = 〈l',e',u'〉 → ∀i. Exists ? (λx.\fst x = i) l → present ?? e' i. #l elim l [ #e #u #l' #e' #u' #E whd in E:(??%?); #i destruct (E) * | * #id #t #tl #IH #e #u #l' #e' #u' #E #i whd in E:(??%?) ⊢ (% → ?); * [ whd in ⊢ (??%? → ?) #E1 (?:e' = add ?? y id r) [ 2: destruct (E) @refl ] (* XXX workaround because destruct overnormalises *) whd >lookup_add_hit % #A destruct | #H change in E:(??(match % with [ _ ⇒ ? ])?) with (populate_env e u tl) lapply (refl ? (populate_env e u tl)) cases (populate_env e u tl) in (*E:%*) ⊢ (???% → ?) (* XXX if I do this directly it rewrites both sides of the equality *) * #rs #e1 #u1 #E1 >E1 in E; whd in ⊢ (??%? → ?) cases (fresh RegisterTag u1) #r #u'' whd in ⊢ (??%? → ?) #E >(?:e' = add ?? e1 id r) [ 2: destruct (E) @refl ] (* XXX workaround because destruct overnormalises *) @lookup_add_oblivious @(IH … E1 ? H) ] ] qed. lemma populate_extends : ∀l,e,u,l',e',u'. populate_env e u l = 〈l',e',u'〉 → ∀i. present ?? e i → present ?? e' i. #l elim l [ #e #u #l' #e' #u' #E whd in E:(??%?); destruct // | * #id #t #tl #IH #e #u #l' #e' #u' #E whd in E:(??%?); change in E:(??(match % with [ _ ⇒ ?])?) with (populate_env e u tl) lapply (refl ? (populate_env e u tl)) cases (populate_env e u tl) in (*E:%*) ⊢ (???% → ?) * #l0 #e0 #u0 #E0 >E0 in E; whd in ⊢ (??%? → ?) cases (fresh RegisterTag u0) #i1 #u1 #E whd in E:(??%?) >(?:e' = add ?? e0 id i1) [ 2: destruct (E) @refl ] #i #H @lookup_add_oblivious @(IH … E0) @H ] qed. definition populate_label_env : label_env → universe LabelTag → list (identifier Label) → label_env × (universe LabelTag) ≝ λen,gen. foldr ?? (λid,engen. let 〈en,gen〉 ≝ engen in let 〈r,gen'〉 ≝ fresh … gen in 〈add ?? en id r, gen'〉) 〈en, gen〉. lemma populates_label_env : ∀ls,lbls,u,lbls',u'. populate_label_env lbls u ls = 〈lbls',u'〉 → ∀l. Exists ? (λl'.l' = l) ls → present ?? lbls' l. #ls elim ls [ #lbls #u #lbls' #u' #E #l * | #h #t #IH #lbls #u #lbls' #u' whd in ⊢ (??%? → ?) change in ⊢ (??match % with [ _ ⇒ ? ]? → ?) with (populate_label_env ???) lapply (refl ? (populate_label_env lbls u t)) cases (populate_label_env lbls u t) in ⊢ (???% → %) #lbls1 #u1 #E1 whd in ⊢ (??%? → ?) cases (fresh ? u1) #r #gen' whd in ⊢ (??%? → ?) #E >(?:lbls' = add ?? lbls1 h r) [ 2: destruct (E) @refl ] #l * [ #El lookup_add_hit % #Er destruct | #H @lookup_add_oblivious @(IH … E1 ? H) ] ] qed. lemma label_env_contents : ∀ls,lbls,u,lbls',u'. populate_label_env lbls u ls = 〈lbls',u'〉 → ∀l. present ?? lbls' l → Exists ? (λl'.l = l') ls ∨ present ?? lbls l. #ls elim ls [ #lbls #u #lbls' #u' #E #l #H %2 whd in E:(??%?); destruct @H | #h #t #IH #lbls #u #lbls' #u' whd in ⊢ (??%? → ?) change in ⊢ (??match % with [ _ ⇒ ? ]? → ?) with (populate_label_env ???) lapply (refl ? (populate_label_env lbls u t)) cases (populate_label_env lbls u t) in ⊢ (???% → %) #lbls1 #u1 #E1 whd in ⊢ (??%? → ?) cases (fresh ? u1) #r #gen' whd in ⊢ (??%? → ?) #E >(?:lbls' = add ?? lbls1 h r) [ 2: destruct (E) @refl ] #l #H cases (identifier_eq ? l h) [ #El %1 %1 @El | #NE cases (IH … E1 l ?) [ #H' %1 %2 @H' | #H' %2 @H' | whd in H >lookup_add_miss in H // @eq_identifier_elim // #E cases NE /2/ ] ] ] qed. definition lookup_reg : ∀e:env. ∀id. present ?? e id → register ≝ lookup_present ??. definition lookup_label : ∀e:label_env. ∀id. present ?? e id → label ≝ lookup_present ??. (* Check that the domain of one graph is included in another, for monotonicity properties. Note that we don't say anything about the statements. *) definition graph_included : graph statement → graph statement → Prop ≝ λg1,g2. ∀l. present ?? g1 l → present ?? g2 l. lemma graph_inc_trans : ∀g1,g2,g3. graph_included g1 g2 → graph_included g2 g3 → graph_included g1 g3. #g1 #g2 #g3 #H1 #H2 #l #P1 @H2 @H1 @P1 qed. definition lpresent ≝ λlbls:label_env. λl. ∃l'. lookup ?? lbls l' = Some ? l. definition partially_closed : label_env → graph statement → Prop ≝ λe,g. ∀l,s. lookup ?? g l = Some ? s → labels_P (λl. present ?? g l ∨ lpresent e l) s. (* I'd use a single parametrised definition along with internal_function, but it's a pain without implicit parameters. *) record partial_fn (lenv:label_env) : Type[0] ≝ { pf_labgen : universe LabelTag ; pf_reggen : universe RegisterTag ; pf_result : option (register × typ) ; pf_params : list (register × typ) ; pf_locals : list (register × typ) ; pf_stacksize : nat ; pf_graph : graph statement ; pf_closed : partially_closed lenv pf_graph ; pf_entry : Σl:label. present ?? pf_graph l ; pf_exit : Σl:label. present ?? pf_graph l }. inductive fn_graph_included (le:label_env) (f1:partial_fn le) (f2:partial_fn le) : Prop ≝ | fn_graph_inc : graph_included (pf_graph ? f1) (pf_graph ? f2) → fn_graph_included le f1 f2. lemma fn_graph_inc_trans : ∀le,f1,f2,f3. fn_graph_included le f1 f2 → fn_graph_included le f2 f3 → fn_graph_included le f1 f3. #le #f1 #f2 #f3 * #H1 * #H2 % @(graph_inc_trans … H1 H2) qed. lemma fn_graph_included_refl : ∀label_env,f. fn_graph_included label_env f f. #le #f % #l #H @H qed. lemma fn_graph_included_sig : ∀label_env,f,f0. ∀f':Σf':partial_fn label_env. fn_graph_included ? f0 f'. fn_graph_included label_env f f0 → fn_graph_included label_env f f'. #le #f #f0 * #f' #H1 #H2 @(fn_graph_inc_trans … H2 H1) qed. lemma add_statement_inv : ∀le,l,s.∀f. labels_present (pf_graph le f) s → partially_closed le (add … (pf_graph ? f) l s). #le #l #s #f #p #l' #s' #H cases (identifier_eq … l l') [ #E >E in H >lookup_add_hit #E' <(?:s = s') [2:destruct //] @(labels_P_mp … p) #l0 #H %1 @lookup_add_oblivious @H | #NE @(labels_P_mp … (pf_closed ? f l' s' ?)) [ #lx * [ #H %1 @lookup_add_oblivious @H | #H %2 @H ] | >lookup_add_miss in H // @eq_identifier_elim // #E cases NE /2/ ] ] qed. (* Add a statement to the graph, *without* updating the entry label. *) definition fill_in_statement : ∀le. label → ∀s:statement. ∀f:partial_fn le. labels_present (pf_graph ? f) s → Σf':partial_fn le. fn_graph_included le f f' ≝ λle,l,s,f,p. mk_partial_fn le (pf_labgen ? f) (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (add ?? (pf_graph ? f) l s) ? «pf_entry ? f, ?» «pf_exit ? f, ?». [ @add_statement_inv @p | 2,3: @lookup_add_oblivious @use_sig | % #l' @lookup_add_oblivious ] qed. (* Add a statement to the graph, making it the entry label. *) definition add_to_graph : ∀le. label → ∀s:statement. ∀f:partial_fn le. labels_present (pf_graph ? f) s → Σf':partial_fn le. fn_graph_included le f f' ≝ λle,l,s,f,p. mk_partial_fn le (pf_labgen ? f) (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (add ?? (pf_graph ? f) l s) ? «l, ?» «pf_exit ? f, ?». [ @add_statement_inv @p | whd >lookup_add_hit % #E destruct | @lookup_add_oblivious @use_sig | % #l' @lookup_add_oblivious ] qed. (* Add a statement with a fresh label to the start of the function. The statement is parametrised by the *next* instruction's label. *) definition add_fresh_to_graph : ∀le. ∀s:(label → statement). ∀f:partial_fn le. (∀l. present ?? (pf_graph ? f) l → labels_present (pf_graph ? f) (s l)) → Σf':partial_fn le. fn_graph_included le f f' ≝ λle,s,f,p. let 〈l,g〉 ≝ fresh … (pf_labgen ? f) in let s' ≝ s (pf_entry ? f) in (mk_partial_fn le g (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (add ?? (pf_graph ? f) l s') ? «l, ?» «pf_exit ? f, ?»). [ % #l' @lookup_add_oblivious | @add_statement_inv @p @use_sig | whd >lookup_add_hit % #E destruct | @lookup_add_oblivious @use_sig ] qed. (* Variants for labels which are (goto) labels *) lemma add_statement_inv' : ∀le,l,s.∀f. labels_P (λl. present ?? (pf_graph le f) l ∨ lpresent le l) s → partially_closed le (add … (pf_graph ? f) l s). #le #l #s #f #p #l' #s' #H cases (identifier_eq … l l') [ #E >E in H >lookup_add_hit #E' <(?:s = s') [2:destruct //] @(labels_P_mp … p) #l0 * [ #H %1 @lookup_add_oblivious @H | #H %2 @H ] | #NE @(labels_P_mp … (pf_closed ? f l' s' ?)) [ #lx * [ #H %1 @lookup_add_oblivious @H | #H %2 @H ] | >lookup_add_miss in H // @eq_identifier_elim // #E cases NE /2/ ] ] qed. definition add_fresh_to_graph' : ∀le. ∀s:(label → statement). ∀f:partial_fn le. (∀l. present ?? (pf_graph ? f) l → labels_P (λl.present ?? (pf_graph ? f) l ∨ lpresent le l) (s l)) → Σf':partial_fn le. fn_graph_included le f f' ≝ λle,s,f,p. let 〈l,g〉 ≝ fresh … (pf_labgen ? f) in let s' ≝ s (pf_entry ? f) in (mk_partial_fn le g (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (add ?? (pf_graph ? f) l s') ? «l, ?» «pf_exit ? f, ?»). [ % #l' @lookup_add_oblivious | @add_statement_inv' @p @use_sig | whd >lookup_add_hit % #E destruct | @lookup_add_oblivious @use_sig ] qed. definition fresh_reg : ∀le. ∀f:partial_fn le. typ → register × (Σf':partial_fn le. fn_graph_included le f f') ≝ λle,f,ty. let 〈r,g〉 ≝ fresh … (pf_reggen ? f) in 〈r, «mk_partial_fn le (pf_labgen ? f) g (pf_result ? f) (pf_params ? f) (〈r,ty〉::(pf_locals ? f)) (pf_stacksize ? f) (pf_graph ? f) (pf_closed ? f) (pf_entry ? f) (pf_exit ? f), ?»〉. % #l // qed. axiom UnknownVariable : String. definition choose_reg : ∀le. ∀env:env.∀ty.∀e:expr ty. ∀f:partial_fn le. expr_vars ty e (present ?? env) → register × (Σf':partial_fn le. fn_graph_included le f f') ≝ λle,env,ty,e,f. match e return λty,e. expr_vars ty e (present ?? env) → register × (Σf':partial_fn le. fn_graph_included le f f') with [ Id _ i ⇒ λEnv. 〈lookup_reg env i Env, «f, ?»〉 | _ ⇒ λ_.fresh_reg le f ty ]. % // qed. let rec foldr_all (A,B:Type[0]) (P:A → Prop) (f:∀a:A. P a → B → B) (b:B) (l:list A) (H:All ? P l) on l :B ≝ match l return λx.All ? P x → B with [ nil ⇒ λ_. b | cons a l ⇒ λH. f a (proj1 … H) (foldr_all A B P f b l (proj2 … H))] H. definition exprtyp_present ≝ λenv:env.λe:Σt:typ.expr t.match e with [ dp ty e ⇒ expr_vars ty e (present ?? env) ]. definition choose_regs : ∀le. ∀env:env. ∀es:list (Σt:typ.expr t). ∀f:partial_fn le. All ? (exprtyp_present env) es → list register × (Σf':partial_fn le. fn_graph_included le f f') ≝ λle,env,es,f,Env. foldr_all (Σt:typ.expr t) ?? (λe,p,acc. let 〈rs,f〉 ≝ acc in let 〈r,f'〉 ≝ match e return λe.? → ? with [ dp t e ⇒ λp.choose_reg le env t e (eject … f) ? ] p in 〈r::rs,«eject … f', ?»〉) 〈[ ], «f, ?»〉 es Env. [ @p | @fn_graph_inc_trans [ 3: @(use_sig ?? f') | skip | @(use_sig ?? f) ] | % // ] qed. lemma extract_pair : ∀A,B,C,D. ∀u:A×B. ∀Q:A → B → C×D. ∀x,y. ((let 〈a,b〉 ≝ u in Q a b) = 〈x,y〉) → ∃a,b. 〈a,b〉 = u ∧ Q a b = 〈x,y〉. #A #B #C #D * #a #b #Q #x #y normalize #E1 %{a} %{b} % try @refl @E1 qed. lemma choose_regs_length : ∀le,env,es,f,p,rs,f'. choose_regs le env es f p = 〈rs,f'〉 → |es| = |rs|. #le #env #es #f elim es [ #p #rs #f normalize #E destruct @refl | * #ty #e #t #IH #p #rs #f' whd in ⊢ (??%? → ??%?) #E cases (extract_pair ???????? E) #rs' * #f'' * #E1 #E2 -E; cases (extract_pair ???????? E2) #r * #f3 * #E3 #E4 -E2; destruct (E4) skip (E1 E3) @eq_f @IH [ @(proj2 … p) | 3: @sym_eq @E1 | 2: skip ] ] qed. lemma present_inc : ∀le,f,l. ∀f':Σf':partial_fn le. fn_graph_included le f f'. present ?? (pf_graph le f) l → present ?? (pf_graph le f') l. #le #f #l * #f' * #H1 #H2 @H1 @H2 qed. axiom BadCminorProgram : String. let rec add_expr (le:label_env) (env:env) (ty:typ) (e:expr ty) (Env:expr_vars ty e (present ?? env)) (dst:register) (f:partial_fn le) on e: Σf':partial_fn le. fn_graph_included le f f' ≝ match e return λty,e.expr_vars ty e (present ?? env) → Σf':partial_fn le. fn_graph_included le f f' with [ Id t i ⇒ λEnv. let r ≝ lookup_reg env i Env in match register_eq r dst with [ inl _ ⇒ «f, ?» | inr _ ⇒ «eject … (add_fresh_to_graph ? (St_op1 t t (Oid t) dst r) f ?), ?» ] | Cst _ c ⇒ λ_. «add_fresh_to_graph ? (St_const dst c) f ?, ?» | Op1 t t' op e' ⇒ λEnv. let 〈r,f〉 ≝ choose_reg ? env ? e' f Env in let f ≝ add_fresh_to_graph ? (St_op1 t t' op dst r) f ? in let f ≝ add_expr ? env ? e' Env r f in «eject … f, ?» | Op2 _ _ _ op e1 e2 ⇒ λEnv. let 〈r1,f〉 ≝ choose_reg ? env ? e1 f (proj1 … Env) in let 〈r2,f〉 ≝ choose_reg ? env ? e2 f (proj2 … Env) in let f ≝ add_fresh_to_graph ? (St_op2 op dst r1 r2) f ? in let f ≝ add_expr ? env ? e2 (proj2 … Env) r2 f in let f ≝ add_expr ? env ? e1 (proj1 … Env) r1 f in «eject … f, ?» | Mem _ _ q e' ⇒ λEnv. let 〈r,f〉 ≝ choose_reg ? env ? e' f Env in let f ≝ add_fresh_to_graph ? (St_load q r dst) f ? in let f ≝ add_expr ? env ? e' Env r f in «eject … f, ?» | Cond _ _ _ e' e1 e2 ⇒ λEnv. let resume_at ≝ pf_entry ? f in let f ≝ add_expr ? env ? e2 (proj2 … Env) dst f in let lfalse ≝ pf_entry ? f in let f ≝ add_fresh_to_graph ? (λ_.St_skip resume_at) f ? in let f ≝ add_expr ? env ? e1 (proj2 … (proj1 … Env)) dst f in let 〈r,f〉 as E ≝ choose_reg ? env ? e' f (proj1 … (proj1 … Env)) in let f ≝ add_fresh_to_graph ? (λltrue. St_cond r ltrue lfalse) f ? in let f ≝ add_expr ? env ? e' (proj1 … (proj1 … Env)) r f in «eject … f, ?» | Ecost _ l e' ⇒ λEnv. let f ≝ add_expr ? env ? e' Env dst f in let f ≝ add_fresh_to_graph ? (St_cost l) f ? in «f, ?» ] Env. (* For new labels, we need to step back through the definitions of f until we hit the point that it was added. *) try @fn_graph_included_refl try (#l #H @H) [ 7: #l #H whd % [ @H | @present_inc @present_inc @present_inc @(use_sig ? (present ???)) ] | 8: #l #H @present_inc @(use_sig ? (present ???)) (* For the monotonicity properties, we just keep going back until we're at the start. The repeat tactical helps here. *) | *: repeat @fn_graph_included_sig @fn_graph_included_refl ] qed. let rec add_exprs (le:label_env) (env:env) (es:list (Σt:typ.expr t)) (Env:All ? (exprtyp_present env) es) (dsts:list register) (pf:|es|=|dsts|) (f:partial_fn le) on es: Σf':partial_fn le. fn_graph_included le f f' ≝ match es return λes.All ?? es → |es|=|dsts| → ? with [ nil ⇒ λ_. match dsts return λx. ?=|x| → Σf':partial_fn le. fn_graph_included le f f' with [ nil ⇒ λ_. «f, ?» | cons _ _ ⇒ λpf.⊥ ] | cons e et ⇒ λEnv. match dsts return λx. ?=|x| → ? with [ nil ⇒ λpf.⊥ | cons r rt ⇒ λpf. let f ≝ add_exprs ? env et ? rt ? f in match e return λe.exprtyp_present ? e → ? with [ dp ty e ⇒ λEnv. let f ≝ add_expr ? env ty e ? r f in «eject … f, ?» ] (proj1 ?? Env) ] ] Env pf. [ // | 2,3: normalize in pf; destruct | @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_refl | @Env | @(proj2 … Env) | normalize in pf; destruct @e0 ] qed. axiom UnknownLabel : String. axiom ReturnMismatch : String. definition stmt_inv : env → label_env → stmt → Prop ≝ λenv,lenv. stmt_P (λs. stmt_vars (present ?? env) s ∧ stmt_labels (present ?? lenv) s). (* Trick to avoid multiplying the proof obligations for the non-Id cases. *) definition expr_is_Id : ∀t. expr t → option ident ≝ λt,e. match e with [ Id _ id ⇒ Some ? id | _ ⇒ None ? ]. (* XXX Work around odd disambiguation errors. *) alias id "R_skip" = "cic:/matita/cerco/RTLabs/syntax/statement.con(0,1,0)". alias id "R_return" = "cic:/matita/cerco/RTLabs/syntax/statement.con(0,14,0)". definition nth_sig : ∀A. ∀P:A → Prop. errmsg → (Σl:list A. All A P l) → nat → res (Σa:A. P a) ≝ λA,P,m,l,n. match nth_opt A n l return λx.(∀_.x = ? → ?) → ? with [ None ⇒ λ_. Error ? m | Some a ⇒ λH'. OK ? «a, ?» ] (All_nth A P n l (use_sig … l)). @H' @refl qed. lemma lookup_label_rev : ∀lenv,l,l',p. lookup_label lenv l p = l' → lookup ?? lenv l = Some ? l'. #lenv #l #l' #p cut (∃lx. lookup ?? lenv l = Some ? lx) [ whd in p; cases (lookup ?? lenv l) in p ⊢ % [ * #H cases (H (refl ??)) | #lx #_ %{lx} @refl ] | * #lx #E whd in ⊢ (??%? → ?) cases p >E #q whd in ⊢ (??%? → ?) #E' >E' @refl ] qed. lemma lookup_label_rev' : ∀lenv,l,p. lookup ?? lenv l = Some ? (lookup_label lenv l p). #lenv #l #p @lookup_label_rev [ @p | @refl ] qed. lemma lookup_label_lpresent : ∀lenv,l,p. lpresent lenv (lookup_label lenv l p). #le #l #p whd %{l} @lookup_label_rev' qed. (* We need to show that the graph only grows, and that Cminor labels will end up in the graph. *) definition Cminor_labels_added ≝ λle,s,f'. ∀l. Exists ? (λl'.l=l') (labels_of s) → ∃l'. lookup ?? le l = Some ? l' ∧ present ?? (pf_graph le f') l'. record add_stmt_inv (le:label_env) (s:stmt) (f:partial_fn le) (f':partial_fn le) : Prop ≝ { stmt_graph_inc : fn_graph_included ? f f' ; stmt_labels_added : Cminor_labels_added le s f' }. lemma empty_Cminor_labels_added : ∀le,s,f'. labels_of s = [ ] → Cminor_labels_added le s f'. #le #s #f' #E whd >E #l *; qed. lemma equal_Cminor_labels_added : ∀le,s,s',f. labels_of s = labels_of s' → Cminor_labels_added le s' f → Cminor_labels_added le s f. #le #s #s' #f #E whd in ⊢ (% → %) > E #H @H qed. lemma fn_graph_included_inv : ∀label_env,s,f,f0. ∀f':Σf':partial_fn label_env. add_stmt_inv label_env s f0 f'. fn_graph_included label_env f f0 → fn_graph_included label_env f f'. #label_env #s #f #f0 * #f' * #H1 #H2 #H3 @(fn_graph_inc_trans … H3 H1) qed. lemma present_inc' : ∀le,s,f,l. ∀f':(Σf':partial_fn le. add_stmt_inv le s f f'). present ?? (pf_graph le f) l → present ?? (pf_graph le f') l. #le #s #f #l * #f' * * #H1 #H2 #H3 @H1 @H3 qed. lemma Cminor_labels_inv : ∀le,s,s',f. ∀f':Σf':partial_fn le. add_stmt_inv le s' f f'. Cminor_labels_added le s f → Cminor_labels_added le s f'. #le #s #s' #f * #f' * #H1 #H2 #H3 #l #E cases (H3 l E) #l' * #L #P %{l'} % [ @L | @present_inc' @P ] qed. lemma Cminor_labels_sig : ∀le,s,f. ∀f':Σf':partial_fn le. fn_graph_included le f f'. Cminor_labels_added le s f → Cminor_labels_added le s f'. #le #s #f * #f' #H1 #H2 #l #E cases (H2 l E) #l' * #L #P %{l'} % [ @L | @present_inc @P ] qed. let rec add_stmt (env:env) (label_env:label_env) (s:stmt) (Env:stmt_inv env label_env s) (f:partial_fn label_env) (exits:Σls:list label. All ? (present ?? (pf_graph ? f)) ls) on s : res (Σf':partial_fn label_env. add_stmt_inv label_env s f f') ≝ match s return λs.stmt_inv env label_env s → res (Σf':partial_fn label_env. add_stmt_inv ? s f f') with [ St_skip ⇒ λ_. OK ? «f, ?» | St_assign _ x e ⇒ λEnv. let dst ≝ lookup_reg env x (π1 (π1 Env)) in OK ? «eject … (add_expr ? env ? e (π2 (π1 Env)) dst f), ?» | St_store _ _ q e1 e2 ⇒ λEnv. let 〈val_reg, f〉 ≝ choose_reg ? env ? e2 f (π2 (π1 Env)) in let 〈addr_reg, f〉 ≝ choose_reg ? env ? e1 f (π1 (π1 Env)) in let f ≝ add_fresh_to_graph ? (St_store q addr_reg val_reg) f ? in let f ≝ add_expr ? env ? e1 (π1 (π1 Env)) addr_reg f in OK ? «eject … (add_expr ? env ? e2 (π2 (π1 Env)) val_reg f), ?» | St_call return_opt_id e args ⇒ λEnv. let return_opt_reg ≝ match return_opt_id return λo. ? → ? with [ None ⇒ λ_. None ? | Some id ⇒ λEnv. Some ? (lookup_reg env id ?) ] Env in let 〈args_regs, f〉 as Eregs ≝ choose_regs ? env args f (π2 (π1 Env)) in let f ≝ match expr_is_Id ? e with [ Some id ⇒ add_fresh_to_graph ? (St_call_id id args_regs return_opt_reg) f ? | None ⇒ let 〈fnr, f〉 ≝ choose_reg ? env ? e f (π2 (π1 (π1 Env))) in let f ≝ add_fresh_to_graph ? (St_call_ptr fnr args_regs return_opt_reg) f ? in «eject … (add_expr ? env ? e (π2 (π1 (π1 Env))) fnr f), ?» ] in OK ? «eject … (add_exprs ? env args (π2 (π1 Env)) args_regs ? f), ?» | St_tailcall e args ⇒ λEnv. let 〈args_regs, f〉 as Eregs ≝ choose_regs ? env args f (π2 (π1 Env)) in let f ≝ match expr_is_Id ? e with [ Some id ⇒ add_fresh_to_graph ? (λ_. St_tailcall_id id args_regs) f ? | None ⇒ let 〈fnr, f〉 ≝ choose_reg ? env ? e f (π1 (π1 Env)) in let f ≝ add_fresh_to_graph ? (λ_. St_tailcall_ptr fnr args_regs) f ? in «eject … (add_expr ? env ? e (π1 (π1 Env)) fnr f), ?» ] in OK ? «eject … (add_exprs ? env args (π2 (π1 Env)) args_regs ? f), ?» | St_seq s1 s2 ⇒ λEnv. do f2 ← add_stmt env label_env s2 ? f «exits, ?»; do f1 ← add_stmt env label_env s1 ? f2 «exits, ?»; OK ? «eject … f1, ?» | St_ifthenelse _ _ e s1 s2 ⇒ λEnv. let l_next ≝ pf_entry ? f in do f2 ← add_stmt env label_env s2 (π2 Env) f «exits, ?»; let l2 ≝ pf_entry ? f2 in let f ≝ add_fresh_to_graph ? (λ_. R_skip l_next) f2 ? in do f1 ← add_stmt env label_env s1 (π2 (π1 Env)) f «exits, ?»; let 〈r,f〉 ≝ choose_reg ? env ? e f1 (π1 (π1 (π1 Env))) in let f ≝ add_fresh_to_graph ? (λl1. St_cond r l1 l2) f ? in OK ? «eject … (add_expr ? env ? e (π1 (π1 (π1 Env))) r f), ?» | St_loop s ⇒ λEnv. let f ≝ add_fresh_to_graph ? R_skip f ? in (* dummy statement, fill in afterwards *) let l_loop ≝ pf_entry ? f in do f ← add_stmt env label_env s (π2 Env) f «exits, ?»; OK ? «eject … (fill_in_statement ? l_loop (R_skip (pf_entry ? f)) f ?), ?» | St_block s ⇒ λEnv. do f ← add_stmt env label_env s (π2 Env) f («pf_entry ? f::exits, ?»); OK ? «eject … f, ?» | St_exit n ⇒ λEnv. do l ← nth_sig ?? (msg BadCminorProgram) exits n; OK ? «eject … (add_fresh_to_graph ? (λ_. R_skip l) f ?), ?» | St_switch sz sg e tab n ⇒ λEnv. let 〈r,f〉 ≝ choose_reg ? env ? e f ? in do l_default ← nth_sig ?? (msg BadCminorProgram) exits n; let f ≝ add_fresh_to_graph ? (λ_. R_skip l_default) f ? in do f ← foldr ? (res (Σf':partial_fn ?. ?)) (λcs,f. do f ← f; let 〈i,n〉 ≝ cs in let 〈cr,f〉 ≝ fresh_reg … f (ASTint sz sg) in let 〈br,f〉 ≝ fresh_reg … f (ASTint I8 Unsigned) in do l_case ← nth_sig ?? (msg BadCminorProgram) exits n; let f ≝ add_fresh_to_graph ? (St_cond br l_case) f ? in let f ≝ add_fresh_to_graph ? (St_op2 (Ocmpu Ceq) (* signed? *) br r cr) f ? in let f ≝ add_fresh_to_graph ? (St_const cr (Ointconst ? i)) f ? in OK ? «eject … f, ?») (OK ? f) tab; OK ? «eject … (add_expr ? env ? e (π1 Env) r f), ?» | St_return opt_e ⇒ let f0 ≝ f in let f ≝ add_fresh_to_graph ? (λ_. R_return) f ? in match opt_e return λo. stmt_inv ?? (St_return o) → res (Σf':partial_fn label_env.add_stmt_inv ? (St_return o) f0 f') with [ None ⇒ λEnv. OK ? «eject … f, ?» | Some e ⇒ match pf_result ? f with [ None ⇒ λEnv. Error ? (msg ReturnMismatch) | Some r ⇒ match e return λe.stmt_inv env label_env (St_return (Some ? e)) → res (Σf':partial_fn label_env.add_stmt_inv label_env (St_return (Some ? e)) f0 f') with [ dp ty e ⇒ λEnv. let f ≝ add_expr label_env env ty e ? (\fst r) f in OK ? «eject … f, ?» ] ] ] | St_label l s' ⇒ λEnv. do f ← add_stmt env label_env s' (π2 Env) f exits; let l' ≝ lookup_label label_env l ? in OK ? «eject … (add_to_graph ? l' (R_skip (pf_entry ? f)) f ?), ?» | St_goto l ⇒ λEnv. let l' ≝ lookup_label label_env l ? in OK ? «eject … (add_fresh_to_graph' ? (λ_.R_skip l') f ?), ?» | St_cost l s' ⇒ λEnv. do f ← add_stmt env label_env s' (π2 Env) f exits; OK ? «eject … (add_fresh_to_graph ? (St_cost l) f ?), ?» ] Env. try @(π1 Env) try @(π2 Env) try @(π1 (π1 Env)) try @(π2 (π1 Env)) try @mk_add_stmt_inv try (@empty_Cminor_labels_added @refl) try (@(All_mp … (use_sig ?? exits))) try @fn_graph_included_refl try (repeat @fn_graph_included_inv repeat @fn_graph_included_sig @fn_graph_included_refl) try (#l #H @I) try (#l #H @H) [ -f @(choose_regs_length … (sym_eq … Eregs)) | @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_refl | whd in Env @(π1 (π1 (π1 Env))) | -f @(choose_regs_length … (sym_eq … Eregs)) | @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_refl | #l #H cases (Exists_append … H) [ #H1 @(stmt_labels_added ???? (use_sig ?? f1) ? H1) | #H2 @(Cminor_labels_inv … H2) @(stmt_labels_added ???? (use_sig ?? f2)) ] | #l #H @present_inc' @H | #l #H @present_inc' @use_sig | @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_inv @fn_graph_included_sig @fn_graph_included_inv @fn_graph_included_refl | #l #H cases (Exists_append … H) [ #H1 @(Cminor_labels_sig … H1) @Cminor_labels_sig @Cminor_labels_sig @(stmt_labels_added ???? (use_sig ?? f1)) | #H2 @(Cminor_labels_sig … H2) @Cminor_labels_sig @Cminor_labels_sig @Cminor_labels_inv @Cminor_labels_sig @(stmt_labels_added ???? (use_sig ?? f2)) ] | #l #H % [ @H | @present_inc @present_inc' @present_inc @(use_sig ?? (pf_entry ? f2)) ] | #l #H @present_inc @present_inc' @H | #l #H @present_inc @H | @(use_sig ?? (pf_entry ??)) | @fn_graph_included_sig @fn_graph_included_inv @fn_graph_included_sig @fn_graph_included_refl | @Cminor_labels_sig @(equal_Cminor_labels_added ?? s) [ @refl | @(stmt_labels_added ???? (use_sig ? (add_stmt_inv ???) ?)) ] | % [ @use_sig | @(use_sig ?? exits) ] | @(equal_Cminor_labels_added ?? s) [ @refl | @(stmt_labels_added ???? (use_sig ? (add_stmt_inv ???) ?)) ] | #l #H @use_sig | #l #H @present_inc @use_sig | #l #H % [ @present_inc @present_inc @present_inc @present_inc @use_sig | @H ] | @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_sig @fn_graph_included_refl | @use_sig | @fn_graph_included_sig @fn_graph_included_inv @fn_graph_included_refl | #l1 * [ #E >E %{l'} % [ @lookup_label_rev' | whd >lookup_add_hit % #E' destruct (E') ] |@Cminor_labels_sig @(stmt_labels_added ???? (use_sig ? (add_stmt_inv ???) ?)) ] | #l1 #H whd %2 @lookup_label_lpresent | @fn_graph_included_sig @fn_graph_included_inv @fn_graph_included_refl | @(equal_Cminor_labels_added ?? s') [ @refl | @Cminor_labels_sig @(stmt_labels_added ???? (use_sig ? (add_stmt_inv ???) ?)) ] ] qed. (* definition mk_fn : ∀le. partial_fn le → internal_function ≝ λle, f. mk_internal_function (pf_labgen ? f) (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (pf_graph ? f) ? (pf_entry ? f) (pf_exit ? f). #l #s #E @(labels_P_mp … (pf_closed ? f l s E)) #l' * [ // | #H *) definition c2ra_function (*: internal_function → internal_function*) ≝ λf. let labgen0 ≝ new_universe LabelTag in let reggen0 ≝ new_universe RegisterTag in let cminor_labels ≝ labels_of (f_body f) in let 〈params, env1, reggen1〉 as E1 ≝ populate_env (empty_map …) reggen0 (f_params f) in let 〈locals0, env, reggen2〉 as E2 ≝ populate_env env1 reggen1 (f_vars f) in let 〈result, locals, reggen〉 ≝ match f_return f with [ None ⇒ 〈None ?, locals0, reggen2〉 | Some ty ⇒ let 〈r,gen〉 ≝ fresh … reggen2 in 〈Some ? 〈r,ty〉, 〈r,ty〉::locals0, gen〉 ] in let 〈label_env, labgen1〉 as El ≝ populate_label_env (empty_map …) labgen0 cminor_labels in let 〈l,labgen〉 ≝ fresh … labgen1 in let emptyfn ≝ mk_partial_fn label_env labgen reggen result params locals (f_stacksize f) (add ?? (empty_map …) l St_return) ? l l in do f ← add_stmt env label_env (f_body f) ? emptyfn [ ]; do u1 ← check_universe_ok ? (pf_labgen ? f); do u2 ← check_universe_ok ? (pf_reggen ? f); OK ? (mk_internal_function (pf_labgen ? f) (pf_reggen ? f) (pf_result ? f) (pf_params ? f) (pf_locals ? f) (pf_stacksize ? f) (pf_graph ? f) ? (pf_entry ? f) (pf_exit ? f) ). [ @I | -emptyfn @(stmt_P_mp … (f_inv f)) #s * #V #L % [ @(stmt_vars_mp … V) #i #H cases (Exists_append … H) [ #H1 @(populate_extends ?????? (sym_eq … E2)) @(populates_env … (sym_eq … E1)) @H1 | #H1 @(populates_env … (sym_eq … E2)) @H1 ] | @(stmt_labels_mp … L) #l #H @(populates_label_env … (sym_eq … El)) @H ] | #l #s #E @(labels_P_mp … (pf_closed ? f l s E)) #l' * [ // | * #l #H cases f #f' * #L #P cases (P l ?) [ #lx >H * #Ex >(?:lx = l') [ 2: destruct (Ex) @refl ] #P' @P' | cases (label_env_contents … (sym_eq ??? El) l ?) [ #H @H | whd in ⊢ (% → ?) whd in ⊢ (?(??%?) → ?) * #H cases (H (refl ??)) | whd >H % #E' destruct (E') ] ] ] | #l1 #s #LOOKUP cases (lookup_add_cases ??????? LOOKUP) [ * #E1 #E2 >E2 @I | whd in ⊢ (??%? → ?) #E' destruct (E') ] | *: whd >lookup_add_hit % #E destruct ] qed. definition cminor_noinit_to_rtlabs : Cminor_noinit_program → res RTLabs_program ≝ λp.transform_partial_program … p (transf_partial_fundef … c2ra_function). include "Cminor/initialisation.ma". definition cminor_to_rtlabs : Cminor_program → res RTLabs_program ≝ λp. let p' ≝ replace_init p in cminor_noinit_to_rtlabs p'.