diff options
Diffstat (limited to 'src/RewriterWf1.v')
-rw-r--r-- | src/RewriterWf1.v | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/RewriterWf1.v b/src/RewriterWf1.v index 49af85a60..411287bcc 100644 --- a/src/RewriterWf1.v +++ b/src/RewriterWf1.v @@ -27,6 +27,7 @@ Require Import Crypto.Util.Prod. Require Import Crypto.Util.Sigma. Require Import Crypto.Util.Sigma.Related. Require Import Crypto.Util.ListUtil.SetoidList. +Require Import Crypto.Util.ListUtil.Forall. Require Import Crypto.Util.ListUtil. Require Import Crypto.Util.Option. Require Import Crypto.Util.Logic.ExistsEqAnd. @@ -2569,5 +2570,304 @@ Module Compilers. End with_interp. End with_var. End Compile. + + Module Reify. + Import Compile. + Import Rewriter.Compilers.RewriteRules.Compile. + Import Rewriter.Compilers.RewriteRules.Reify. + + Local Notation type := (type.type base.type). + Local Notation expr := (@expr.expr base.type ident). + Local Notation value := (@value base.type ident). + Local Notation UnderLets := (@UnderLets.UnderLets base.type ident). + + Ltac wf_ctors := + repeat first [ match goal with + | [ |- UnderLets.wf _ _ (UnderLets.Base _) (UnderLets.Base _) ] => constructor + | [ |- expr.wf _ (_ @ _) (_ @ _) ] => constructor + | [ |- expr.wf ?seg (#_) (#_) ] + => (tryif is_evar seg then instantiate (1:=nil) else idtac); + constructor + | [ |- expr.wf _ ($_) ($_) ] => constructor + | [ |- expr.wf _ (expr.Abs _) (expr.Abs _) ] => constructor; intros + | [ |- expr.wf _ (UnderLets.to_expr _) (UnderLets.to_expr _) ] => apply UnderLets.wf_to_expr + | [ H : expr.wf ?G ?x ?y |- expr.wf ?seg ?x ?y ] => first [ is_evar seg | constr_eq G seg ]; exact H + | [ H : List.Forall2 (expr.wf _) ?x ?y |- List.Forall2 (expr.wf _) ?x ?y ] + => eapply Forall2_Proper_impl; [ | reflexivity | reflexivity | exact H ]; repeat intro + | [ H : List.Forall2 (expr.wf ?G) ?x ?y |- List.Forall2 (expr.wf ?seg) ?x ?y ] + => first [ is_evar seg | constr_eq seg G ]; exact H + | [ H : List.Forall2 ?P ?x ?y |- List.Forall2 ?Pe ?x ?y ] + => first [ is_evar Pe | constr_eq Pe P ]; exact H + | [ H : forall x y, List.In (x, y) ?G -> expr.wf ?G' x y, H' : List.In (?v1, ?v2) ?G |- expr.wf ?seg ?v1 ?v2 ] + => first [ is_evar seg | constr_eq seg G' ]; exact (H _ _ H') + | [ |- expr.wf _ (reify_list _) (reify_list _) ] + => rewrite expr.wf_reify_list + | [ H : expr.wf _ (reify_list ?xs) (reify_list ?ys) |- List.Forall2 _ ?xs ?xy ] + => rewrite expr.wf_reify_list in H + | [ |- ?G ] => tryif has_evar G then fail else solve [ destruct_head'_ex; subst; wf_t ] + end ]. + Ltac handle_wf_rec do_try := + let tac _ + := solve + [ repeat + first + [ progress wf_ctors + | handle_wf_rec do_try + | match goal with + | [ |- List.In ?v ?seg ] => is_evar seg; unify seg (cons v nil) + | [ |- List.In ?v (?seg1 ++ ?seg2) ] + => rewrite in_app_iff; + first [ is_evar seg1; left + | is_evar seg2; right ] + (*| [ |- ?x ++ ?y = ?x ++ ?z ] => apply f_equal2*) + | [ |- ?x = ?y ] + => is_evar x; tryif has_evar y then fail else reflexivity + | [ |- forall t v1 v2, List.In (existT _ t (v1, v2)) (?x ++ ?G1) -> List.In (existT _ t (v1, v2)) (?x ++ ?G2) ] + => is_evar G2; + tryif first [ has_evar x | has_evar G1 ] then fail else (do 3 intro; exact id) + end ] ] in + match goal with + | [ H : expr.wf ?segv ?x1 ?x2 + |- UnderLets.wf _ ?Gv (nat_rect _ _ _ _ ?x1) (nat_rect _ _ _ _ ?x2) ] + => unshelve + (eapply UnderLets.wf_Proper_list; + [ | | eapply @UnderLets.wf_nat_rect_arrow with (R' := fun G' => expr.wf G') (seg:=segv) (G:=Gv); intros ]; + [ try (intros; subst; match goal with |- expr.wf _ _ _ => shelve end).. ]; + [ try (intros; subst; match goal with |- UnderLets.wf _ _ _ _ => shelve end).. ]; + [ try match goal with |- _ = _ => shelve end.. ]); + shelve_unifiable; + do_try tac + | [ H : expr.wf ?segv ?x1 ?x2 + |- UnderLets.wf _ ?Gv (list_rect _ _ _ _ ?x1) (list_rect _ _ _ _ ?x2) ] + => unshelve + (eapply UnderLets.wf_Proper_list; + [ | | eapply @UnderLets.wf_list_rect_arrow with (R' := fun G' => expr.wf G') (seg:=segv) (G:=Gv); intros ]; + [ try (intros; subst; match goal with |- expr.wf _ _ _ => shelve end).. ]; + [ try (intros; subst; match goal with |- UnderLets.wf _ _ _ _ => shelve end).. ]; + [ try match goal with |- _ = _ => shelve end.. ]); + shelve_unifiable; + do_try tac + | [ |- UnderLets.wf _ _ ?x ?y ] + => let f := head x in + let g := head y in + is_var f; is_var g; + unshelve + (lazymatch goal with + | [ H : context[UnderLets.wf _ _ (f _) (g _)] |- _ ] + => eapply UnderLets.wf_Proper_list; [ | | eapply H ] + | [ H : context[UnderLets.wf _ _ (f _ _) (g _ _)] |- _ ] + => eapply UnderLets.wf_Proper_list; [ | | eapply H ] + | [ H : context[UnderLets.wf _ _ (f _ _ _) (g _ _ _)] |- _ ] + => eapply UnderLets.wf_Proper_list; [ | | eapply H ] + | [ H : context[UnderLets.wf _ _ (f _ _ _ _) (g _ _ _ _)] |- _ ] + => eapply UnderLets.wf_Proper_list; [ | | eapply H ] + end; + [ try (intros; subst; match goal with |- expr.wf _ _ _ => shelve end).. ]; + [ try (intros; subst; match goal with |- UnderLets.wf _ _ _ _ => shelve end).. ]; + [ try match goal with |- _ = _ => shelve end.. ]); + shelve_unifiable; + do_try tac + end. + + Ltac reify_wf_t_step := + first [ progress subst + | match goal with + | [ H : invert_expr.reflect_list ?v = Some _, H' : invert_expr.reflect_list ?v' = None |- _ ] + => first [ erewrite <- expr.wf_reflect_list in H' by eassumption + | erewrite -> expr.wf_reflect_list in H' by eassumption ]; + exfalso; clear -H H'; congruence + end + | progress inversion_option + | progress destruct_head'_False + | progress intros + | progress cbn [invert_expr.invert_Literal invert_expr.ident.invert_Literal value' type.interp base.interp base.base_interp] in * + | match goal with + | [ H : ident.Literal _ = ident.Literal _ |- _ ] + => pose proof (f_equal invert_expr.ident.invert_Literal H); clear H + end + | progress expr.inversion_wf_constr + | break_innermost_match_hyps_step + | progress expr.inversion_wf_one_constr + | progress expr.invert_subst + | progress expr.inversion_expr + | progress expr.invert_match + | progress wf_ctors + | match goal with + | [ |- UnderLets.wf _ _ (nat_rect _ _ _ _) (nat_rect _ _ _ _) ] + => apply UnderLets.wf_nat_rect; intros + | [ |- UnderLets.wf _ ?G (list_rect _ _ _ _) (list_rect _ _ _ _) ] + => apply @UnderLets.wf_list_rect with (RA := expr.wf G) + | [ |- UnderLets.wf _ _ (UnderLets.splice _ _) (UnderLets.splice _ _) ] + => apply @UnderLets.wf_splice with (P := fun G => expr.wf G); intros; subst + | [ H : expr.wf _ (reify_list ?l1) (reify_list ?l2) + |- expr.wf ?G (nth_default ?d1 ?l1 ?n) (nth_default ?d2 ?l2 ?n) ] + => cut (List.Forall2 (expr.wf G) l1 l2 /\ expr.wf G d1 d2); + [ rewrite Forall2_forall_iff''; + let H := fresh in intro H; apply H + | split ] + | [ |- ?x = ?x ] => reflexivity + end + | progress handle_wf_rec ltac:(fun tac => try tac (); tac ()) ]. + Ltac reify_wf_t := repeat reify_wf_t_step. + + Section with_var. + Context {var1 var2 : type -> Type}. + + Lemma wf_reflect_ident_iota G {t} (idc : ident t) + : option_eq + (wf_value G) + (@reflect_ident_iota var1 t idc) + (@reflect_ident_iota var2 t idc). + Proof using Type. + destruct idc; cbv [reflect_ident_iota option_eq]; try reflexivity. + all: cbv [wf_value wf_value']; intros; subst; break_innermost_match; cbn [reify reflect] in *; + lazymatch goal with + | [ H : invert_expr.reflect_list ?v = Some _, H' : invert_expr.reflect_list ?v' = None |- _ ] + => first [ erewrite <- expr.wf_reflect_list in H' by eassumption + | erewrite -> expr.wf_reflect_list in H' by eassumption ]; + exfalso; clear -H H'; congruence + | _ => idtac + end; + expr.invert_subst; subst. + all: reify_wf_t. + Qed. + + Lemma wf_reflect_expr_beta_iota + {ident} + {reflect_ident_iota1 reflect_ident_iota2} + (Hwf_reflect_ident_iota + : forall G {t} (idc : ident t), + option_eq + (@wf_value _ ident var1 var2 G _) + (@reflect_ident_iota1 t idc) + (@reflect_ident_iota2 t idc)) + G G' + (HG' : forall t v1 v2, List.In (existT _ t (v1, v2)) G' -> wf_value G v1 v2) + {t} e1 e2 + (Hwf : expr.wf G' e1 e2) + : UnderLets.wf + (fun G'' => wf_value G'') + G + (@reflect_expr_beta_iota ident var1 reflect_ident_iota1 t e1) + (@reflect_expr_beta_iota ident var2 reflect_ident_iota2 t e2). + Proof using Type. + revert G HG'; induction Hwf; cbn [reflect_expr_beta_iota]; intros. + all: repeat first [ match goal with + | [ |- UnderLets.wf _ _ _ _ ] => constructor + | [ |- expr.wf _ _ _ ] => constructor + | [ |- wf_value' _ (UnderLets.Base _) (UnderLets.Base _) ] => constructor + | [ Hwf_reflect_ident_iota : forall G t' idc', option_eq (wf_value G) (?reflect_ident_iota1 t' idc') (?reflect_ident_iota2 t' idc'), + H1 : ?reflect_ident_iota1 ?t ?idc = _, H2 : ?reflect_ident_iota2 ?t ?idc = _ |- _ ] + => let H' := fresh in + pose proof (fun G => Hwf_reflect_ident_iota G t idc) as H'; + rewrite H1, H2 in H'; clear H1 H2; cbv [option_eq] in H' + | [ H : list _ -> ?T |- _ ] => specialize (H nil) + | [ |- UnderLets.wf ?Pv ?Gv (UnderLets.splice _ _) (UnderLets.splice _ _) ] + => apply @UnderLets.wf_splice with (P:=fun G => wf_value G); intros; subst + | [ H : context[reflect_expr_beta_iota] |- UnderLets.wf _ _ (reflect_expr_beta_iota _ _) (reflect_expr_beta_iota _ _) ] + => apply H; intros + | [ |- wf_value _ (fun x => _) (fun y => _) ] => hnf; intros; subst + | [ |- wf_value' _ (splice_under_lets_with_value _ _) (splice_under_lets_with_value _ _) ] + => apply wf_splice_under_lets_with_value + | [ |- UnderLets.wf (fun G a1 a2 => wf_value_with_lets G (Base_value a1) (Base_value a2)) ?G' ?x ?y ] + => cut (UnderLets.wf (fun G => wf_value G) G' x y); + [ apply UnderLets.wf_Proper_list_impl; cbv [wf_value_with_lets Base_value] + | ] + end + | progress destruct_head'_False + | progress inversion_option + | solve [ auto ] + | break_innermost_match_step + | apply wf_reflect + | apply wf_reify + | progress intros + | progress cbn [List.In eq_rect fst snd] in * + | progress destruct_head'_or + | progress inversion_sigma + | progress subst + | progress inversion_prod + | cbn [wf_value wf_value'] in *; + handle_wf_rec ltac:(fun tac => try tac (); try eassumption; tac ()) + | eapply wf_value'_Proper_list; [ | match goal with H : _ |- _ => now eapply H end ]; solve [ destruct_head'_ex; subst; wf_t ] + | match goal with + | [ H : wf_value _ ?f ?g |- wf_value _ (?f _) (?g _) ] + => eapply wf_value'_Proper_list; revgoals; [ hnf in H; eapply H; revgoals | ]; try eassumption; try reflexivity; now destruct_head'_ex; subst; wf_t + end ]. + Qed. + + Lemma wf_reify_expr_beta_iota + {ident} + {reflect_ident_iota1 reflect_ident_iota2} + (Hwf_reflect_ident_iota + : forall G {t} (idc : ident t), + option_eq + (@wf_value _ ident var1 var2 G _) + (@reflect_ident_iota1 t idc) + (@reflect_ident_iota2 t idc)) + G G' + (HG' : forall t v1 v2, List.In (existT _ t (v1, v2)) G' -> wf_value G v1 v2) + {t} e1 e2 + (Hwf : expr.wf G' e1 e2) + : UnderLets.wf + (fun G'' => expr.wf G'') + G + (@reify_expr_beta_iota ident var1 reflect_ident_iota1 t e1) + (@reify_expr_beta_iota ident var2 reflect_ident_iota2 t e2). + Proof using Type. + cbv [reify_expr_beta_iota reify_to_UnderLets]. + eapply @UnderLets.wf_splice with (P := fun G => wf_value G); + intros; destruct_head'_ex; subst. + all: repeat first [ break_innermost_match_step + | progress cbn [reflect reify] in * + | progress fold (@reflect ident var1) (@reflect ident var2) + | progress fold (@reify ident var1) (@reify ident var2) + | progress intros + | assumption + | apply wf_reify + | apply wf_reflect + | eapply wf_reflect_expr_beta_iota + | match goal with + | [ |- List.In ?x ?seg ] => is_evar seg; unify seg (cons x nil); left + end + | constructor + | match goal with H : _ |- _ => eapply H; revgoals; clear H end ]. + Qed. + + Lemma wf_expr_value_to_rewrite_rule_replacement + {ident} + {reflect_ident_iota1 reflect_ident_iota2} + (Hwf_reflect_ident_iota + : forall G {t} (idc : ident t), + option_eq + (@wf_value _ ident var1 var2 G _) + (@reflect_ident_iota1 t idc) + (@reflect_ident_iota2 t idc)) + (should_do_again : bool) + G {t} e1 e2 + (Hwf : @wf_maybe_do_again_expr ident var1 var2 t true true G e1 e2) + : UnderLets.wf + (fun G' => @wf_maybe_do_again_expr ident var1 var2 t should_do_again should_do_again G') + G + (@expr_value_to_rewrite_rule_replacement ident var1 reflect_ident_iota1 should_do_again t e1) + (@expr_value_to_rewrite_rule_replacement ident var2 reflect_ident_iota2 should_do_again t e2). + Proof using Type. + cbv [expr_value_to_rewrite_rule_replacement]. + eapply @UnderLets.wf_splice with (P := @wf_maybe_do_again_expr ident var1 var2 _ true true); intros; destruct_head'_ex; subst. + { destruct Hwf as [G' [HG' Hwf] ]. + eapply UnderLets.wf_flat_map; + cbv [wf_value] in *; + eauto using wf_value'_Proper_list, UnderLets.wf_of_expr, wf_reify_expr_beta_iota. + { intros; eapply wf_reflect; now repeat constructor. } } + { repeat first [ progress cbv [wf_maybe_do_again_expr] in * + | break_innermost_match_step + | progress destruct_head'_ex + | progress destruct_head'_and + | progress subst + | eapply wf_reify_expr_beta_iota; try eassumption + | constructor + | solve [ eauto ] ]. } + Qed. + End with_var. + End Reify. End RewriteRules. End Compilers. |