include "RTLabs/RTLabs_syntax.ma". include "RTL/RTL.ma". include "common/FrontEndOps.ma". include "common/Graphs.ma". include "joint/TranslateUtils.ma". include alias "ASM/BitVector.ma". include alias "arithmetics/nat.ma". definition size_of_sig_type ≝ λsig. match sig with [ ASTint isize sign ⇒ match isize with [ I8 ⇒ 1 | I16 ⇒ 2 | I32 ⇒ 4 ] | ASTptr ⇒ 2 (* rgn ⇒ nat_of_bitvector ? ptr_size *) ]. definition sign_of_sig_type ≝ λsig. match sig with [ ASTint _ sign ⇒ sign | ASTptr ⇒ Unsigned ]. inductive register_type: Type[0] ≝ | register_int: register → register_type | register_ptr: register → register → register_type. definition local_env ≝ identifier_map RegisterTag (list register). definition local_env_typed : list (register × typ) → local_env → Prop ≝ λl,env.All ? (λp.let 〈r, ty〉 ≝ p in ∃regs.lookup … env r = Some ? regs ∧ |regs| = size_of_sig_type ty) l. definition find_local_env ≝ λr.λlenv : local_env. λprf : r ∈ lenv.opt_safe … (lookup … lenv r) ?. lapply (in_map_domain … lenv r) >prf * #x #lookup_eq >lookup_eq % #ABS destruct(ABS) qed. lemma find_local_env_elim : ∀P : list register → Prop.∀r. ∀lenv: local_env.∀prf. (∀x.lookup … lenv r = Some ? x → P x) → P (find_local_env r lenv prf). #P#r#lenv#prf #H change with (P (opt_safe ???)) @opt_safe_elim assumption qed. definition find_local_env_arg : register → local_env → ? → list psd_argument ≝ λr,lenv,prf. map … (Reg ?) (find_local_env r lenv prf). (* move *) let rec m_iter (M : Monad) X (f : X → M X) (n : ℕ) (m : M X) on n : M X ≝ match n with [ O ⇒ m | S k ⇒ ! v ← m ; m_iter … f k (f v) ]. definition fresh_registers : ∀p,g.ℕ → state_monad (joint_internal_function p g) (list register) ≝ λp,g,n. let f ≝ λacc.! m ← fresh_register … ; return (m :: acc) in m_iter … f n (return [ ]). include alias "common/Identifiers.ma". let rec map_list_local_env lenv (regs : list (register×typ)) on regs : All ? (λpr.bool_to_Prop (\fst pr ∈ lenv)) regs → list register ≝ match regs return λx.All ?? x → ? with [ nil ⇒ λ_.[ ] | cons hd tl ⇒ λprf.find_local_env (\fst hd) lenv ? @ map_list_local_env lenv tl ? ].cases prf #A #B assumption qed. definition initialize_local_env : ∀globals. list (register×typ) → state_monad (joint_internal_function RTL globals) local_env ≝ λglobals,registers. let f ≝ λr_sig,lenv. let 〈r, sig〉 ≝ r_sig in let size ≝ size_of_sig_type sig in ! regs ← fresh_registers … size ; return add … lenv r regs in m_fold … f registers (empty_map …). lemma initialize_local_env_in : ∀globals,l,def,r. Exists ? (λx.\fst x = r) l → r ∈ \snd (initialize_local_env globals l def). whd in match initialize_local_env; normalize nodelta #globals cut (∀l,init,def,r.(Exists ? (λx.\fst x = r) l ∨ bool_to_Prop (r ∈ init)) → r ∈ \snd (m_fold (state_monad ?) ??? l init def)) [7: #aux #l #def #r #H @aux %1{H} |*:] #l elim l -l [ #init #def #r * [*] #H @H ] * #hd #sig #tl #IH #init #def #r #H whd in ⊢ (?(???(???%)?)); normalize nodelta whd in ⊢ (?(???(???(match % with [ _ ⇒ ?]))?)); inversion (fresh_registers ????) #def' #regs #EQfresh normalize nodelta @IH cases H -H [*] #H [ destruct %2 @mem_set_add_id | %1{H} | %2 >mem_set_add @orb_Prop_r @H ] qed. example proj1_rewrite : ∀A,B,a,b.∀pr : A×B.〈a,b〉 = pr → a = \fst pr. // qed-. example proj2_rewrite : ∀A,B,a,b.∀pr : A×B.〈a,b〉 = pr → b = \snd pr. // qed-. definition initialize_locals_params_ret : ∀globals. (* locals *) list (register×typ) → (* params *) list (register×typ) → (* return *) option (register×typ) → state_monad (joint_internal_function RTL globals) local_env ≝ λglobals,locals,params,ret,def. let 〈def',lenv〉 as EQ ≝ initialize_local_env globals ((match ret with [ Some r_sig ⇒ [r_sig] | None ⇒ [ ] ]) @ locals @ params) def in let params' ≝ map_list_local_env lenv params ? in let ret' ≝ match ret return λx.ret = x → ? with [ Some r_sig ⇒ λprf.find_local_env (\fst r_sig) lenv ? | None ⇒ λ_.[ ] ] (refl …) in let def'' ≝ mk_joint_internal_function RTL globals (joint_if_luniverse … def') (joint_if_runiverse … def') ret' params' (joint_if_stacksize … def') (joint_if_local_stacksize … def') (joint_if_code … def') (joint_if_entry … def') in 〈def'', lenv〉. @hide_prf [ >(proj2_rewrite ????? EQ) @initialize_local_env_in >prf %1 % |*: >(proj2_rewrite ????? EQ) @(All_mp ??? (λpr.initialize_local_env_in ??? (\fst pr))) @(All_mp … (λpr.Exists ? (λx.\fst x = \fst pr) params)) [ #a #H @Exists_append_r @Exists_append_r @H | elim params [%] #hd #tl #IH % [ %1 % ] @(All_mp … IH) #x #G %2{G} ] ] qed. definition make_addr ≝ λA. λlst: list A. λprf: 2 = length A lst.〈nth_safe … 0 lst ?, nth_safe … 1 lst ?〉. EQ % ] qed. definition split_into_bytes: ∀size. ∀int: bvint size. Σbytes: list Byte. |bytes| = size_intsize size ≝ λsize,int.reverse … (vrsplit ? (size_intsize size) 8 int). >length_reverse @pi2 qed. let rec list_inject_All_aux A P (l : list A) on l : All A P l → list (Σx.P x) ≝ match l return λx.All A P x → list (Σx.P x) with [ nil ⇒ λ_.[ ] | cons hd tl ⇒ λprf.«hd, proj1 … prf» :: list_inject_All_aux A P tl (proj2 … prf) ]. definition translate_op_aux: ∀globals. Op2 → ∀dests : list register. ∀srcrs1 : list psd_argument. ∀srcrs2 : list psd_argument. |dests| = |srcrs1| → |srcrs1| = |srcrs2| → list (joint_seq RTL globals) ≝ λglobals: list ident. λop. λdestrs. λsrcrs1. λsrcrs2. λprf1,prf2. (* first, clear carry if op relies on it *) map3 ???? (OP2 RTL globals op) destrs srcrs1 srcrs2 prf1 prf2. definition translate_op: ∀globals. Op2 → ∀dests : list register. ∀srcrs1 : list psd_argument. ∀srcrs2 : list psd_argument. |dests| = |srcrs1| → |srcrs1| = |srcrs2| → list (joint_seq RTL globals) ≝ λglobals: list ident. λop. λdestrs. λsrcrs1. λsrcrs2. match op with [ Add ⇒ match destrs return λdestrs.|destrs| = |srcrs1| → |srcrs1| = |srcrs2| → ? with [ nil ⇒ λ_.λ_.[ ] | cons destr destrs' ⇒ match srcrs1 return λsrcrs1.S(|destrs'|) = |srcrs1| → |srcrs1| = |srcrs2| → ? with [ nil ⇒ λprf1.⊥ | cons srcr1 srcrs1' ⇒ λprf1. match srcrs2 return λsrcrs2.S(|srcrs1'|) = |srcrs2| → ? with [ nil ⇒ λprf2.⊥ | cons srcr2 srcrs2' ⇒ λprf2.OP2 ?? Add destr srcr1 srcr2 :: translate_op_aux … Addc destrs' srcrs1' srcrs2' ?? ] ] ] | Sub ⇒ λprf1,prf2.[ CLEAR_CARRY ?? ] @ translate_op_aux … Sub … prf1 prf2 | Addc ⇒ λprf1,prf2.[ CLEAR_CARRY ?? ] @ translate_op_aux … Addc … prf1 prf2 | _ ⇒ translate_op_aux … op destrs srcrs1 srcrs2 ]. normalize in prf1 prf2; destruct assumption qed. definition cast_list : ∀A.A → ℕ → list A → list A ≝ λA,deflt,new_length,l. if leb (|l|) new_length then l @ make_list ? deflt (new_length - |l|) else lhd … l new_length. lemma length_make_list: ∀A: Type[0]. ∀elt: A. ∀n: nat. length ? (make_list A elt n) = n. #A #ELT #N elim N normalize // qed. lemma length_lhd : ∀A,l,n.|lhd A l n| = min (|l|) n. #A #l elim l -l [ * // | #hd #tl #IH * normalize [%] #n >IH normalize elim (leb ??) % ] qed. lemma length_cast_list : ∀A,dflt,n,l.|cast_list A dflt n l| = n. #A #dflt #n #l normalize @leb_elim #H normalize [ >length_append >length_make_list @sym_eq @minus_to_plus // | >length_lhd normalize @leb_elim [ #abs elim (absurd ? abs H) ] #_ % ] qed. definition translate_op_asym_unsigned : ∀globals.Op2 → list register → list psd_argument → list psd_argument → list (joint_seq RTL globals) ≝ λglobals,op,destrs,srcrs1,srcrs2. let l ≝ |destrs| in let srcrs1' ≝ cast_list ? (zero_byte : psd_argument) l srcrs1 in let srcrs2' ≝ cast_list ? (zero_byte : psd_argument) l srcrs2 in translate_op globals op destrs srcrs1' srcrs2' ??. @hide_prf normalize nodelta >length_cast_list [2: >length_cast_list ] % qed. definition zero_args : ∀size.Σl : list psd_argument.|l| = size ≝ λsize. «make_list psd_argument (zero_byte) size, length_make_list …». definition one_args : ∀size.Σl : list psd_argument.|l| = size ≝ λsize.match size return λsize.Σl : list psd_argument.|l| = size with [ O ⇒ «[ ], refl …» | S k ⇒ (byte_of_nat 1 : psd_argument) :: zero_args k ]. whd in ⊢ (??%?); @eq_f @pi2 qed. definition size_of_cst ≝ λtyp.λcst : constant typ.match cst with [ Ointconst size _ _ ⇒ size_intsize size | _ ⇒ 2 ]. definition cst_well_defd : ∀ty.list ident → constant ty → Prop ≝ λty,globals,cst. match cst with [ Oaddrsymbol id _ ⇒ bool_to_Prop (id ∈ globals) | _ ⇒ True ]. definition translate_cst : ∀ty. ∀globals: list ident. ∀cst_sig: Σcst : constant ty.cst_well_defd ty globals cst. ∀destrs: list register. |destrs| = size_of_cst ? cst_sig → bind_new register (list (joint_seq RTL globals)) ≝ λty,globals,cst_sig,destrs. match pi1 … cst_sig in constant return λty'.λx : constant ty'. cst_well_defd ty' ? x → |destrs| = size_of_cst ty' x → ? with [ Ointconst size sign const ⇒ λcst_prf,prf. map2 … (λr.λb : Byte.r ← b) destrs (split_into_bytes size const) ? | Oaddrsymbol id offset ⇒ λcst_prf,prf. let 〈r1, r2〉 ≝ make_addr … destrs ? in let off ≝ bitvector_of_nat 16 offset in [ ADDRESS RTL globals id ? off r1 r2 ] | Oaddrstack offset ⇒ λcst_prf,prf. let 〈r1, r2〉 ≝ make_addr … destrs ? in (rtl_stack_address r1 r2 : joint_seq RTL globals) :: if eqb offset 0 then [ ] else translate_op … Add [r1 ; r2 ] [ r1 ; r2 ] [ byte_of_nat … offset ; zero_byte ] (refl …) (refl …) ] (pi2 … cst_sig). @hide_prf [ cases (split_into_bytes ??) #lst #EQ >EQ >prf whd in ⊢ (??%?); cases size % | @cst_prf |*: >prf % ] qed. definition translate_move : ∀globals. ∀destrs: list register. ∀srcrs: list psd_argument. |destrs| = |srcrs| → list (joint_seq RTL globals) ≝ λglobals,destrs,srcrs,length_eq. map2 … (λdst,src.dst ← src) destrs srcrs length_eq. definition sign_mask : ∀globals.register → psd_argument → list (joint_seq RTL globals) ≝ (* this sets destr to 0xFF if s is neg, 0x00 o.w. Done like that: byte in destr if srcr is: neg | pos destr ← srcr | 127 11...1 | 01...1 destr ← destr length_make_list % qed. definition translate_fill_with_zero : ∀globals : list ident. list register → list (joint_seq RTL globals) ≝ λglobals,destrs. translate_move ? destrs (zero_args (|destrs|)) ?. @sym_eq @pi2 qed. let rec last A (l : list A) on l : option A ≝ match l with [ nil ⇒ None ? | cons hd tl ⇒ match tl with [ nil ⇒ Some ? hd | _ ⇒ last A tl ] ]. lemma last_def : ∀A,hd,tl.last A (hd @ [tl]) = Some ? tl. #A #hd elim hd -hd [ #tl % ] #hd * [ #_ #last % ] #hd' #tl #IH #last @IH qed. lemma last_not_empty : ∀A,l.not_empty A l → match last A l with [ None ⇒ False | _ ⇒ True ]. #A @list_elim_left [*] #pref #last #_ #_ >last_def % qed. definition translate_op_asym_signed : (* first argument will dictate size, second will be casted signedly *) ∀globals.Op2 → list register → list psd_argument → list psd_argument → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,op,destrs,srcrs1,srcrs2. νtmp1,tmp2 in let l ≝ |destrs| in let cast_srcrs ≝ λsrcrs,tmp. let srcrs_l ≝ |srcrs| in if leb (S srcrs_l) l then match last ? srcrs with [ Some last ⇒ 〈srcrs @ make_list … (Reg ? tmp) (l - srcrs_l), sign_mask … tmp last〉 | None ⇒ 〈make_list … (zero_byte : psd_argument) l, [ ]〉 ] else 〈lhd … srcrs l, [ ]〉 in let prf : ∀srcrs,tmp.|destrs| = |\fst (cast_srcrs srcrs tmp)| ≝ ? in let srcrs1init ≝ cast_srcrs srcrs1 tmp1 in let srcrs2init ≝ cast_srcrs srcrs2 tmp2 in \snd srcrs1init @@ \snd srcrs2init @@ translate_op globals op destrs (\fst srcrs1init) (\fst srcrs2init) ??. @hide_prf [ @prf | length_make_list % | #_ >length_append >length_make_list @minus_to_plus [ @(transitive_le … H) ] // ] | >length_lhd lapply (le_S_S_to_le … (not_le_to_lt … H)) lapply (|destrs|) lapply (|srcrs|) -destrs #n #m * -n [2: #n #H] whd in ⊢ (???%); [2: @if_elim #_ % ] >not_le_to_leb_false [%] @lt_to_not_le @le_S_S assumption ] qed. (* using size of lists as size of ints *) definition translate_cast : ∀globals: list ident. signedness → list register → list register → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,src_sign,destrs,srcrs. match reduce_strong ?? srcrs destrs with [ mk_Sig t prf ⇒ let src_common ≝ \fst (\fst t) in let src_rest ≝ \snd (\fst t) in let dst_common ≝ \fst (\snd t) in let dst_rest ≝ \snd (\snd t) in (* first, move the common part *) translate_move ? dst_common (map … (Reg ?) src_common) ? @@ match src_rest return λ_.bind_new ?? with [ nil ⇒ (* upcast *) match src_sign return λ_.bind_new ?? with [ Unsigned ⇒ translate_fill_with_zero ? dst_rest | Signed ⇒ match last … srcrs (* = src_common *) with [ Some src_last ⇒ translate_cast_signed ? dst_rest src_last | None ⇒ (* srcrs is empty *) translate_fill_with_zero ? dst_rest ] ] | _ ⇒ (* downcast, nothing else to do *) [ ] ] ]. >length_map >prf % qed. definition translate_notint : ∀globals : list ident. ∀destrs : list register. ∀srcrs_arg : list register. |destrs| = |srcrs_arg| → list (joint_seq RTL globals) ≝ λglobals, destrs, srcrs, prf. map2 ??? (OP1 RTL globals Cmpl) destrs srcrs prf. definition translate_negint : ∀globals.? → ? → ? → list (joint_seq RTL globals) ≝ λglobals: list ident. λdestrs: list register. λsrcrs: list register. λprf: |destrs| = |srcrs|. (* assert in caml code *) translate_notint … destrs srcrs prf @ translate_op ? Add destrs (map … (Reg ?) destrs) (one_args (|destrs|)) ??. @hide_prf >length_map [ @sym_eq @pi2 | % ] qed. definition translate_notbool: ∀globals : list ident. list register → list register → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,destrs,srcrs. match destrs with [ nil ⇒ [ ] | cons destr destrs' ⇒ translate_fill_with_zero ? destrs' @@ match srcrs return λ_.bind_new ?? with [ nil ⇒ [destr ← zero_byte] | cons srcr srcrs' ⇒ (destr ← srcr) ::: map register (joint_seq RTL globals) (λr. destr ← destr .Or. r) srcrs' @@ (* now destr is non-null iff srcrs was non-null *) CLEAR_CARRY ?? ::: (* many uses of 0, better not use immediates *) ν tmp in [tmp ← zero_byte ; destr ← tmp .Sub. tmp ; (* now carry bit is set iff destr was non-null *) destr ← tmp .Addc. tmp] ] ]. definition translate_op1 : ∀globals.? → ? → ? → ? → ? → ? → ? → bind_new register (list (joint_seq RTL globals)) ≝ λglobals. λty, ty'. λop1: unary_operation ty ty'. λdestrs: list register. λsrcrs: list register. λprf1: |destrs| = size_of_sig_type ty'. λprf2: |srcrs| = size_of_sig_type ty. match op1 return λty'',ty'''.λx : unary_operation ty'' ty'''.ty'' = ty → ty''' = ty' → bind_new register (list (joint_seq RTL globals)) with [ Ocastint _ src_sign _ _ ⇒ λeq1,eq2. translate_cast globals src_sign destrs srcrs | Onegint sz sg ⇒ λeq1,eq2. translate_negint globals destrs srcrs ? | Onotbool _ _ _ _ ⇒ λeq1,eq2. translate_notbool globals destrs srcrs | Onotint sz sg ⇒ λeq1,eq2. translate_notint globals destrs srcrs ? | Optrofint sz sg ⇒ λeq1,eq2. translate_cast globals Unsigned destrs srcrs | Ointofptr sz sg ⇒ λeq1,eq2. translate_cast globals Unsigned destrs srcrs | Oid t ⇒ λeq1,eq2. translate_move globals destrs (map … (Reg ?) srcrs) ? | _ ⇒ λeq1,eq2.? (* float operations implemented in runtime *) ] (refl …) (refl …). @hide_prf destruct >prf1 >prf2 [3: >length_map ] // qed. include alias "arithmetics/nat.ma". definition translate_mul_i : ∀globals. register → register → (* size of destination and sources *) ∀n : ℕ. (* the temporary destination, with a dummy register at the end *) ∀tmp_destrs_dummy : list register. ∀srcrs1,srcrs2 : list psd_argument. |tmp_destrs_dummy| = S n → n = |srcrs1| → |srcrs1| = |srcrs2| → (* the position of the least significant byte of the result we compute at this stage (goes from 0 to n in the main function) *) ∀k : ℕ. lt k n → (* the position of the byte in the first source we will use in this stage. the position in the other source will be k - i *) (Σi.i(plus_n_O (S k)) @le_plus // ] | >length_map % | >length_map >length_ltl >tmp_destrs_dummy_prf >length_append >length_make_list normalize in ⊢ (???(?%?)); cases n in k_prf; [ #ABS cases (absurd ? ABS ?) /2 by le_to_not_lt/ ] #n' #k_prf >minus_S_S plus_minus_commutative [%] @le_S_S_to_le assumption ] qed. definition translate_mul : ∀globals.?→?→?→?→?→bind_new register (list (joint_seq RTL globals)) ≝ λglobals : list ident. λdestrs : list register. λsrcrs1 : list psd_argument. λsrcrs2 : list psd_argument. λsrcrs1_prf : |destrs| = |srcrs1|. λsrcrs2_prf : |srcrs1| = |srcrs2|. (* needed fresh registers *) νa in νb in (* temporary registers for the result are created, so to avoid overwriting sources *) νν |destrs| as tmp_destrs with tmp_destrs_prf in νdummy in (dummy ← byte_of_nat 0) ::: (* the step calculating all products with least significant byte going in the k-th position of the result *) let translate_mul_k : (Σk.k<|destrs|) → list (joint_seq RTL globals) → list (joint_seq RTL globals) ≝ λk_sig,acc.match k_sig with [ mk_Sig k k_prf ⇒ foldr … (translate_mul_i ? a b (|destrs|) (tmp_destrs @ [dummy]) srcrs1 srcrs2 ? srcrs1_prf srcrs2_prf k k_prf) acc (range_strong (S k)) ] in (* initializing tmp_destrs to zero dummy is intentionally uninitialized *) translate_fill_with_zero … tmp_destrs @ (* the main body, roughly: for k in 0 ... n-1 do for i in 0 ... k do translate_mul_i … k … i *) foldr … translate_mul_k [ ] (range_strong (|destrs|)) @ (* epilogue: saving the result *) translate_move … destrs (map … (Reg ?) tmp_destrs) ?. @hide_prf [ >length_append length_map >tmp_destrs_prf // ] qed. definition translate_divumodu8 : ∀globals.?→?→?→?→?→?→ bind_new register (list (joint_seq RTL globals)) ≝ λglobals: list ident. λdiv_not_mod: bool. λdestrs: list register. λsrcrs1: list psd_argument. λsrcrs2: list psd_argument. λsrcrs1_prf : |destrs| = |srcrs1|. λsrcrs2_prf : |srcrs1| = |srcrs2|. match destrs return λx.x = destrs → bind_new ?? with [ nil ⇒ λ_.[ ] | cons destr destrs' ⇒ λeq_destrs. match destrs' with [ nil ⇒ match srcrs1 return λx.x = srcrs1 → bind_new ?? with [ nil ⇒ λeq_srcrs1.⊥ | cons srcr1 srcrs1' ⇒ λeq_srcrs1. match srcrs2 return λx.x = srcrs2 → bind_new ?? with [ nil ⇒ λeq_srcrs2.⊥ | cons srcr2 srcrs2' ⇒ λeq_srcrs2. νdummy in let 〈destr1, destr2〉 ≝ if div_not_mod then 〈destr, dummy〉 else 〈dummy, destr〉 in [❮destr1, destr2❯ ← srcr1 .DivuModu. srcr2] ] (refl …) ] (refl …) | _ ⇒ ? (* not implemented *) ] ] (refl …). [3: elim not_implemented] @hide_prf destruct normalize in srcrs1_prf srcrs2_prf; destruct qed. (* Paolo: to be moved elsewhere *) let rec foldr2 (A : Type[0]) (B : Type[0]) (C : Type[0]) (f : A→B→C→C) (init : C) (l1 : list A) (l2 : list B) (prf : |l1| = |l2|) on l1 : C ≝ match l1 return λx.x = l1 → C with  [ nil ⇒ λ_.init | cons a l1' ⇒ λeq_l1. match l2 return λy.y = l2 → C with [ nil ⇒ λeq_l2.⊥ | cons b l2' ⇒ λeq_l2. f a b (foldr2 A B C f init l1' l2' ?) ] (refl …) ] (refl …). @hide_prf destruct normalize in prf; [destruct|//] qed. definition translate_ne: ∀globals: list ident.?→?→?→?→ bind_new register (list (joint_seq RTL globals)) ≝ λglobals: list ident. λdestrs: list register. λsrcrs1: list psd_argument. λsrcrs2: list psd_argument. match destrs return λ_.|srcrs1| = |srcrs2| → bind_new ?? with [ nil ⇒ λ_.[ ] | cons destr destrs' ⇒ λEQ. translate_fill_with_zero … destrs' @@ match srcrs1 return λx.|x| = |srcrs2| → bind_new ?? with [ nil ⇒ λ_.[destr ← zero_byte] | cons srcr1 srcrs1' ⇒ match srcrs2 return λx.S (|srcrs1'|) = |x| → bind_new ?? with [ nil ⇒ λEQ.⊥ | cons srcr2 srcrs2' ⇒ λEQ. νtmpr in let f : psd_argument → psd_argument → list (joint_seq RTL globals) → list (joint_seq RTL globals) ≝ λs1,s2,acc. tmpr ← s1 .Xor. s2 :: destr ← destr .Or. tmpr :: acc in let epilogue : list (joint_seq RTL globals) ≝ [ CLEAR_CARRY ?? ; tmpr ← zero_byte .Sub. destr ; (* now carry bit is 1 iff destrs != 0 *) destr ← zero_byte .Addc. zero_byte ] in destr ← srcr1 .Xor. srcr2 :: foldr2 ??? f epilogue srcrs1' srcrs2' ? ] ] EQ ]. @hide_prf normalize in EQ; destruct(EQ) assumption qed. (* if destrs is 0 or 1, it inverses it. To be used after operations that ensure this. *) definition translate_toggle_bool : ∀globals.?→bind_new register (list (joint_seq RTL globals)) ≝ λglobals: list ident. λdestrs: list register. match destrs with [ nil ⇒ [ ] | cons destr _ ⇒ [destr ← destr .Xor. byte_of_nat 1] ]. definition translate_lt_unsigned : ∀globals. ∀destrs: list register. ∀srcrs1: list psd_argument. ∀srcrs2: list psd_argument. |srcrs1| = |srcrs2| → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,destrs,srcrs1,srcrs2,srcrs_prf. match destrs with [ nil ⇒ [ ] | cons destr destrs' ⇒ ν tmpr in (translate_fill_with_zero … destrs' @@ (* I perform a subtraction, but the only interest is in the carry bit *) translate_op ? Sub (make_list … tmpr (|srcrs1|)) srcrs1 srcrs2 ? srcrs_prf @@ [ destr ← zero_byte .Addc. zero_byte ]) ]. @hide_prf >length_make_list % qed. (* shifts signed integers by adding 128 to the most significant byte it replaces it with a fresh register which must be provided *) let rec shift_signed globals (tmp : register) (srcrs : list psd_argument) on srcrs : Σt : (list psd_argument) × (list (joint_seq RTL globals)).|\fst t| = |srcrs| ≝ let byte_128 : Byte ≝ true ::: bv_zero ? in match srcrs with [ nil ⇒ 〈[ ],[ ]〉 | cons srcr srcrs' ⇒ match srcrs' with [ nil ⇒ 〈[ Reg ? tmp ], [ tmp ← srcr .Add. byte_128 ]〉 | _ ⇒ let re ≝ shift_signed globals tmp srcrs' in 〈srcr :: \fst re, \snd re〉 ] ]. @hide_prf [1,2: % |*: cases re * #a #b >p1 normalize #EQ >EQ % ] qed. definition translate_lt_signed : ∀globals. ∀destrs: list register. ∀srcrs1: list psd_argument. ∀srcrs2: list psd_argument. |srcrs1| = |srcrs2| → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,destrs,srcrs1,srcrs2,srcrs_prf. νtmp_last_s1 in νtmp_last_s2 in let p1 ≝ shift_signed globals tmp_last_s1 srcrs1 in let new_srcrs1 ≝ \fst p1 in let shift_srcrs1 ≝ \snd p1 in let p2 ≝ shift_signed globals tmp_last_s2 srcrs2 in let new_srcrs2 ≝ \fst p2 in let shift_srcrs2 ≝ \snd p2 in shift_srcrs1 @@ shift_srcrs2 @@ translate_lt_unsigned globals destrs new_srcrs1 new_srcrs2 ?. @hide_prf whd in match new_srcrs1; whd in match new_srcrs2; cases p1 cases p2 // qed. definition translate_lt : bool→∀globals.?→?→?→?→bind_new register (list (joint_seq RTL globals)) ≝ λis_unsigned,globals,destrs,srcrs1,srcrs2,srcrs_prf. if is_unsigned then translate_lt_unsigned globals destrs srcrs1 srcrs2 srcrs_prf else translate_lt_signed globals destrs srcrs1 srcrs2 srcrs_prf. definition translate_cmp ≝ λis_unsigned,globals,cmp,destrs,srcrs1,srcrs2,srcrs_prf. match cmp with [ Ceq ⇒ translate_ne globals destrs srcrs1 srcrs2 srcrs_prf @@ translate_toggle_bool globals destrs | Cne ⇒ translate_ne globals destrs srcrs1 srcrs2 srcrs_prf | Clt ⇒ translate_lt is_unsigned globals destrs srcrs1 srcrs2 srcrs_prf | Cgt ⇒ translate_lt is_unsigned globals destrs srcrs2 srcrs1 ? | Cle ⇒ translate_lt is_unsigned globals destrs srcrs2 srcrs1 ? @@ translate_toggle_bool globals destrs | Cge ⇒ translate_lt is_unsigned globals destrs srcrs1 srcrs2 srcrs_prf @@ translate_toggle_bool globals destrs ]. @sym_eq assumption qed. definition translate_op2 : ∀globals.∀ty1,ty2,ty3.∀op : binary_operation ty1 ty2 ty3. ∀destrs : list register. ∀srcrs1,srcrs2 : list psd_argument. |destrs| = size_of_sig_type ty3 → |srcrs1| = size_of_sig_type ty1 → |srcrs2| = size_of_sig_type ty2 → bind_new register (list (joint_seq RTL globals)) ≝ λglobals,ty1,ty2,ty3,op2,destrs,srcrs1,srcrs2. match op2 return λty1,ty2,ty3.λx : binary_operation ty1 ty2 ty3. ? = size_of_sig_type ty3 → ? = size_of_sig_type ty1 → ? = size_of_sig_type ty2 → bind_new ?? with [ Oadd sz sg ⇒ λprf1,prf2,prf3. translate_op globals Add destrs srcrs1 srcrs2 ?? | Oaddpi sz ⇒ λprf1,prf2,prf3. translate_op_asym_signed globals Add destrs srcrs1 srcrs2 | Oaddip sz ⇒ λprf1,prf2,prf3. translate_op_asym_signed globals Add destrs srcrs2 srcrs1 | Osub sz sg ⇒ λprf1,prf2,prf2. translate_op globals Sub destrs srcrs1 srcrs2 ?? | Osubpi sz ⇒ λprf1,prf2,prf3. translate_op_asym_signed globals Add destrs srcrs1 srcrs2 | Osubpp sz ⇒ λprf1,prf2,prf3. translate_op_asym_unsigned globals Sub destrs srcrs1 srcrs2 | Omul sz sg ⇒ λprf1,prf2,prf3. translate_mul globals destrs srcrs1 srcrs2 ?? | Odivu sz ⇒ λprf1,prf2,prf3. translate_divumodu8 globals true destrs srcrs1 srcrs2 ?? | Omodu sz ⇒ λprf1,prf2,prf3. translate_divumodu8 globals false destrs srcrs1 srcrs2 ?? | Oand sz sg ⇒ λprf1,prf2,prf3. translate_op globals And destrs srcrs1 srcrs2 ?? | Oor sz sg ⇒ λprf1,prf2,prf3. translate_op globals Or destrs srcrs1 srcrs2 ?? | Oxor sz sg ⇒ λprf1,prf2,prf3. translate_op globals Xor destrs srcrs1 srcrs2 ?? | Ocmp sz sg1 sg2 c ⇒ λprf1,prf2,prf3. translate_cmp false globals c destrs srcrs1 srcrs2 ? | Ocmpu sz sg c ⇒ λprf1,prf2,prf3. translate_cmp true globals c destrs srcrs1 srcrs2 ? | Ocmpp sg c ⇒ λprf1,prf2,prf3. translate_cmp true globals c destrs srcrs1 srcrs2 ? | _ ⇒ ⊥ (* assert false, implemented in run time or float op *) ]. try @not_implemented @hide_prf // qed. definition translate_cond: ∀globals: list ident. list register → label → bind_step_block RTL globals ≝ λglobals: list ident. λsrcrs: list register. λlbl_true: label. match srcrs return λ_.bind_step_block RTL ? with [ nil ⇒ bret … [ ] | cons srcr srcrs' ⇒ ν tmpr in let f : register → label → joint_seq RTL globals ≝ λr.λ_. tmpr ← tmpr .Or. r in bret … 〈(λ_.MOVE RTL globals 〈tmpr,srcr〉) :: map ?? f srcrs', λ_.COND … tmpr lbl_true, [ ]〉 ]. (* Paolo: to be controlled (original seemed overly complex) *) definition translate_load : ∀globals.?→?→?→bind_new register ? ≝ λglobals: list ident. λaddr : list psd_argument. λaddr_prf: 2 = |addr|. λdestrs: list register. ν tmp_addr_l in ν tmp_addr_h in (translate_move … [tmp_addr_l ; tmp_addr_h] addr ? @@ let f ≝ λdestr : register.λacc : bind_new register (list (joint_seq RTL globals)). [LOAD RTL globals destr (Reg ? tmp_addr_l) (Reg ? tmp_addr_h)] @@ translate_op ? Add [tmp_addr_l ; tmp_addr_h] [tmp_addr_l ; tmp_addr_h] [(int_size : Byte) ; zero_byte ] ? ? @@ acc in foldr … f [ ] destrs). @hide_prf [ EQ1 #EQ' destruct assumption qed. lemma lenv_typed_arg_typed_ok1 : ∀locals,env,r,ty. local_env_typed locals env → Exists ? (λx:register×typ.〈r,ty〉=x) locals → ∀prf. |find_local_env_arg r env prf| = size_of_sig_type ty. #locals #env #r #ty #env_typed #r_ok #prf whd in match find_local_env_arg; normalize nodelta >length_map @lenv_typed_reg_typed_ok1 assumption qed. lemma lenv_typed_reg_typed_ok2 : ∀locals,env,r,ty. local_env_typed locals env → Exists ? (λx:register×typ.〈r,ty〉=x) locals → r ∈ env. #locals #env #r #ty #env_typed #r_ok elim (Exists_All … r_ok env_typed) * #r' #ty' * #EQ destruct(EQ) * #rs * #EQ1 #EQ2 whd in ⊢ (?%); >EQ1 % qed. lemma cst_size_ok : ∀ty,cst.size_of_sig_type ty=size_of_cst ty cst. #ty * -ty [*] // qed. (* TODO: move it *) definition ensure_bind_step_block : ∀p : params.∀g. bind_new register (list (joint_seq p g)) → bind_step_block p g ≝ λp,g,b.! l ← b; bret ? (step_block p g) l. coercion bind_step_block_from_bind_list nocomposites : ∀p : params.∀g. ∀b : bind_new register (list (joint_seq p g)).bind_step_block p g ≝ ensure_bind_step_block on _b : bind_new register (list (joint_seq ??)) to bind_step_block ??. definition translate_statement : ∀globals, locals.∀env. local_env_typed locals env → ∀stmt : statement.statement_typed locals stmt → 𝚺b : bind_step_block RTL globals + bind_fin_block RTL globals. match b with [ inl _ ⇒ label | _ ⇒ unit] ≝ λglobals,locals,lenv,lenv_typed,stmt. match stmt return λstmt.statement_typed locals stmt → 𝚺b: bind_step_block RTL globals ⊎ bind_fin_block RTL globals.match b with [ inl _ ⇒ label | _ ⇒ unit ] with [ St_skip lbl' ⇒ λstmt_typed. ❬inl … (bret … [ ]), lbl'❭ | St_cost cost_lbl lbl' ⇒ λstmt_typed. ❬inl … (bret … 〈[ ], λ_.COST_LABEL … cost_lbl, [ ]〉), lbl'❭ | St_const ty destr cst lbl' ⇒ λstmt_typed. ❬inl … (translate_cst ty globals cst (find_local_env destr lenv ?) ?), lbl'❭ | St_op1 ty ty' op1 destr srcr lbl' ⇒ λstmt_typed. ❬inl … (translate_op1 globals ty' ty op1 (find_local_env destr lenv ?) (find_local_env srcr lenv ?) ??), lbl'❭ | St_op2 ty1 ty2 ty3 op2 destr srcr1 srcr2 lbl' ⇒ λstmt_typed. ❬inl … (translate_op2 globals … op2 (find_local_env destr lenv ?) (find_local_env_arg srcr1 lenv ?) (find_local_env_arg srcr2 lenv ?) ???), lbl'❭ (* XXX: should we be ignoring this? *) | St_load ignore addr destr lbl' ⇒ λstmt_typed. ❬inl … (translate_load globals (find_local_env_arg addr lenv ?) ? (find_local_env destr lenv ?)), lbl'❭ (* XXX: should we be ignoring this? *) | St_store ignore addr srcr lbl' ⇒ λstmt_typed. ❬inl … (translate_store globals (find_local_env_arg addr lenv ?) ? (find_local_env_arg srcr lenv ?)), lbl'❭ | St_call_id f args retr lbl' ⇒ λstmt_typed. ❬inl … (bret … 〈[ ],λ_.CALL RTL ? (inl ?? f) (rtl_args args lenv ?) (match retr with [ Some retr ⇒ find_local_env retr lenv ? | None ⇒ [ ] ]), [ ]〉), lbl'❭ | St_call_ptr f args retr lbl' ⇒ λstmt_typed. let fs ≝ find_and_addr_arg f lenv ?? in ❬inl … (bret … 〈[ ],λ_.CALL RTL ? (inr ?? fs) (rtl_args args lenv ?) (match retr with [ Some retr ⇒ find_local_env retr lenv ? | None ⇒ [ ] ]), [ ]〉), lbl'❭ | St_cond r lbl_true lbl_false ⇒ λstmt_typed. ❬inl … (translate_cond globals (find_local_env r lenv ?) lbl_true), lbl_false❭ | St_return ⇒ λ_. ❬inr … (bret … 〈[ ], RETURN ?〉),it❭ ]. @hide_prf [ cases daemon (* needs more hypotheses *) | @(lenv_typed_reg_typed_ok2 … lenv_typed stmt_typed) | >(lenv_typed_reg_typed_ok1 … lenv_typed stmt_typed) @cst_size_ok |4,5,6,7: cases stmt_typed #dstr_typed #srcr_typed [3,4: @(lenv_typed_reg_typed_ok1 … lenv_typed) assumption |2: @(lenv_typed_reg_typed_ok2 … lenv_typed srcr_typed) |1: @(lenv_typed_reg_typed_ok2 … lenv_typed dstr_typed) ] |8,9,10,11,12,13: cases stmt_typed * #srcrs1_prf #srcrs2_prf #dstr_prf [5,6: @(lenv_typed_arg_typed_ok1 … lenv_typed) assumption |4: @(lenv_typed_reg_typed_ok1 … lenv_typed) assumption |3: @(lenv_typed_reg_typed_ok2 … lenv_typed srcrs2_prf) |2: @(lenv_typed_reg_typed_ok2 … lenv_typed srcrs1_prf) |1: @(lenv_typed_reg_typed_ok2 … lenv_typed dstr_prf) ] |*: cases daemon (* TODO *) ] qed. definition translate_internal : ∀globals.internal_function → (* insert here more properties *) joint_closed_internal_function RTL globals ≝ λglobals: list ident. λdef. let runiverse' ≝ f_reggen def in let luniverse' ≝ f_labgen def in let stack_size' ≝ f_stacksize def in let entry' ≝ pi1 … (f_entry def) in let init ≝ mk_joint_internal_function RTL globals luniverse' runiverse' [ ] [ ] stack_size' stack_size' (add … (empty_map ? (joint_statement ??)) entry' (RETURN …)) entry' in let 〈init',lenv〉 as pr_eq ≝ initialize_locals_params_ret globals (f_locals def) (f_params def) (f_result def) init in let vars ≝ (f_locals def) @ (f_params def) @ match f_result def with [ Some x ⇒ [x] | _ ⇒ [ ] ] in let f_trans ≝ λlbl,stmt,def. let pr ≝ translate_statement … vars lenv ? stmt ? in match dpi1 … pr return λx.match x with [ inl _ ⇒ label | _ ⇒ unit ] → ? with [ inl instrs ⇒ λlbl'.b_adds_graph … instrs lbl lbl' def | inr instrs ⇒ λ_.b_fin_adds_graph … instrs lbl def ] (dpi2 … pr) in foldi … f_trans (f_graph def) init'. (* TODO *) cases daemon qed. (*CSC: here we are not doing any alignment on variables, like it is done in OCaml because of CompCert heritage *) definition rtlabs_to_rtl: (* initialization cost label *) costlabel → RTLabs_program → rtl_program ≝ λinit_cost, p. mk_joint_program … (prog_funct_names \ldots p) (transform_program … p (λvarnames. transf_fundef … (translate_internal ?))) init_cost ?. @hide_prf @transform_prog_funct_names qed.