From bacfa270c0c492ef8518d360d87e46cee292474f Mon Sep 17 00:00:00 2001 From: Jason Gross Date: Tue, 12 Mar 2019 22:55:21 -0400 Subject: Factor out rewriter rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move rewrite rule definitions, and the proofs about them, into separate files. We don't yet make use of the separate interp proofs of rewrite rules; the next step is to refactor the interp proof machinery so that we can easily prove the relevant interp relations, given the equality proofs in `src/RewriterRulesProofs.v` After | File Name | Before || Change | % Change -------------------------------------------------------------------------------------------- 23m01.93s | Total | 22m37.08s || +0m24.84s | +1.83% -------------------------------------------------------------------------------------------- 0m24.10s | RewriterRulesProofs.vo | N/A || +0m24.10s | ∞ 1m12.13s | Rewriter.vo | 1m20.61s || -0m08.48s | -10.51% 0m41.17s | ExtractionHaskell/unsaturated_solinas | 0m37.57s || +0m03.60s | +9.58% 1m42.40s | Fancy/Barrett256.vo | 1m40.22s || +0m02.18s | +2.17% 0m45.56s | p521_32.c | 0m48.16s || -0m02.59s | -5.39% 0m14.48s | ExtractionOCaml/word_by_word_montgomery.ml | 0m12.47s || +0m02.00s | +16.11% 1m48.48s | RewriterWf2.vo | 1m46.70s || +0m01.77s | +1.66% 0m15.06s | ExtractionOCaml/unsaturated_solinas | 0m14.06s || +0m01.00s | +7.11% 0m06.26s | ExtractionHaskell/unsaturated_solinas.hs | 0m07.29s || -0m01.03s | -14.12% 0m04.71s | ExtractionHaskell/saturated_solinas.hs | 0m06.05s || -0m01.33s | -22.14% 3m22.17s | p384_32.c | 3m23.06s || -0m00.88s | -0.43% 1m57.31s | RewriterRulesInterpGood.vo | 1m56.61s || +0m00.70s | +0.60% 1m35.20s | RewriterRulesGood.vo | 1m35.80s || -0m00.59s | -0.62% 0m57.50s | ExtractionHaskell/word_by_word_montgomery | 0m56.53s || +0m00.96s | +1.71% 0m45.71s | RewriterInterpProofs1.vo | 0m46.13s || -0m00.42s | -0.91% 0m39.66s | p521_64.c | 0m38.90s || +0m00.75s | +1.95% 0m36.22s | PushButtonSynthesis/UnsaturatedSolinas.vo | 0m36.42s || -0m00.20s | -0.54% 0m34.39s | Fancy/Montgomery256.vo | 0m34.45s || -0m00.06s | -0.17% 0m33.16s | RewriterWf1.vo | 0m32.96s || +0m00.19s | +0.60% 0m32.21s | ExtractionHaskell/saturated_solinas | 0m31.53s || +0m00.67s | +2.15% 0m26.94s | PushButtonSynthesis/WordByWordMontgomery.vo | 0m27.20s || -0m00.25s | -0.95% 0m25.89s | SlowPrimeSynthesisExamples.vo | 0m25.59s || +0m00.30s | +1.17% 0m23.37s | ExtractionOCaml/word_by_word_montgomery | 0m22.90s || +0m00.47s | +2.05% 0m21.19s | PushButtonSynthesis/BarrettReduction.vo | 0m20.79s || +0m00.40s | +1.92% 0m18.30s | p256_32.c | 0m18.54s || -0m00.23s | -1.29% 0m18.29s | p448_solinas_64.c | 0m18.58s || -0m00.28s | -1.56% 0m17.92s | secp256k1_32.c | 0m18.41s || -0m00.48s | -2.66% 0m14.06s | p434_64.c | 0m13.92s || +0m00.14s | +1.00% 0m11.61s | ExtractionOCaml/saturated_solinas | 0m11.57s || +0m00.03s | +0.34% 0m08.90s | p224_32.c | 0m09.12s || -0m00.21s | -2.41% 0m08.49s | ExtractionOCaml/unsaturated_solinas.ml | 0m08.85s || -0m00.35s | -4.06% 0m08.45s | ExtractionHaskell/word_by_word_montgomery.hs | 0m08.62s || -0m00.16s | -1.97% 0m08.02s | p384_64.c | 0m07.04s || +0m00.97s | +13.92% 0m07.01s | ExtractionOCaml/saturated_solinas.ml | 0m06.57s || +0m00.43s | +6.69% 0m06.67s | BoundsPipeline.vo | 0m06.87s || -0m00.20s | -2.91% 0m03.39s | PushButtonSynthesis/Primitives.vo | 0m03.44s || -0m00.04s | -1.45% 0m03.36s | PushButtonSynthesis/SmallExamples.vo | 0m03.38s || -0m00.02s | -0.59% 0m03.23s | PushButtonSynthesis/SaturatedSolinas.vo | 0m03.21s || +0m00.02s | +0.62% 0m03.04s | curve25519_32.c | 0m02.68s || +0m00.35s | +13.43% 0m02.74s | PushButtonSynthesis/MontgomeryReduction.vo | 0m02.55s || +0m00.19s | +7.45% 0m02.19s | curve25519_64.c | 0m01.81s || +0m00.37s | +20.99% 0m01.72s | secp256k1_64.c | 0m01.46s || +0m00.26s | +17.80% 0m01.56s | p256_64.c | 0m01.22s || +0m00.34s | +27.86% 0m01.49s | p224_64.c | 0m01.56s || -0m00.07s | -4.48% 0m01.32s | CLI.vo | 0m01.32s || +0m00.00s | +0.00% 0m01.14s | StandaloneHaskellMain.vo | 0m01.08s || +0m00.05s | +5.55% 0m01.06s | CompilersTestCases.vo | 0m01.04s || +0m00.02s | +1.92% 0m01.06s | StandaloneOCamlMain.vo | 0m01.12s || -0m00.06s | -5.35% 0m01.00s | RewriterProofs.vo | 0m01.13s || -0m00.12s | -11.50% 0m00.64s | RewriterRules.vo | N/A || +0m00.64s | ∞ --- src/RewriterRulesProofs.v | 485 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 src/RewriterRulesProofs.v (limited to 'src/RewriterRulesProofs.v') diff --git a/src/RewriterRulesProofs.v b/src/RewriterRulesProofs.v new file mode 100644 index 000000000..0b6317167 --- /dev/null +++ b/src/RewriterRulesProofs.v @@ -0,0 +1,485 @@ +Require Import Coq.micromega.Lia. +Require Import Coq.ZArith.ZArith. +Require Import Crypto.Util.ListUtil Coq.Lists.List Crypto.Util.ListUtil.FoldBool. +(* +Require Import Crypto.Util.Option. +Require Import Crypto.Util.OptionList. +Require Import Crypto.Util.CPSNotations. +Require Import Crypto.Util.Bool.Reflect. + *) +Require Import Crypto.Util.ZRange. +Require Import Crypto.Util.ZRange.Operations. +Require Import Crypto.Util.ZUtil.Definitions. +Require Import Crypto.Util.ZUtil.Notations. +Require Import Crypto.Util.ZUtil.Tactics.LtbToLt. +Require Import Crypto.Util.ZUtil.Tactics.DivModToQuotRem. +Require Import Crypto.Util.ZUtil.Tactics.PullPush.Modulo. +Require Import Crypto.Util.ZUtil.Hints. +Require Import Crypto.Util.ZUtil.Hints.Core. +Require Import Crypto.Util.ZUtil.ZSimplify.Core. +Require Import Crypto.Util.ZUtil.ZSimplify. +Require Import Crypto.Util.ZUtil.ZSimplify.Simple. +Require Import Crypto.Util.ZUtil.Definitions. +Require Import Crypto.Util.ZUtil.AddGetCarry. +Require Import Crypto.Util.ZUtil.MulSplit. +Require Import Crypto.Util.ZUtil.Zselect. +Require Import Crypto.Util.ZUtil.Div. +Require Import Crypto.Util.ZUtil.Modulo. +Require Import Crypto.Util.ZRange. +Require Import Crypto.Util.ZRange.Operations. +Require Import Crypto.Util.ZRange.BasicLemmas. +Require Import Crypto.Util.ZRange.OperationsBounds. +Require Import Crypto.Util.Tactics.NormalizeCommutativeIdentifier. +Require Import Crypto.Util.Tactics.BreakMatch. +Require Import Crypto.Util.Tactics.SplitInContext. +Require Import Crypto.Util.Tactics.SpecializeAllWays. +Require Import Crypto.Util.Tactics.SpecializeBy. +Require Import Crypto.Util.Tactics.RewriteHyp. +Require Import Crypto.Util.Tactics.Head. +Require Import Crypto.Util.Tactics.SetEvars. +Require Import Crypto.Util.Tactics.SubstEvars. +Require Import Crypto.Util.Prod. +Require Import Crypto.Util.Bool. +Require Import Crypto.Util.ListUtil. +Require Import Crypto.Util.ListUtil.Forall. +Require Import Crypto.Util.ListUtil.ForallIn. +Require Import Crypto.Util.NatUtil. +Require Import Crypto.Util.Option. +Require Import Crypto.Util.CPSNotations. +Require Import Crypto.Util.HProp. +Require Import Crypto.Util.Decidable. +Require Crypto.Util.PrimitiveProd. +Require Crypto.Util.PrimitiveHList. +Require Import Crypto.Language. +Require Import Crypto.LanguageWf. +Require Import Crypto.RewriterRules. +Require Import Crypto.Util.LetIn. +Require Import Crypto.Util.Tactics.Head. +Require Import Crypto.Util.Notations. +Import ListNotations. Local Open Scope bool_scope. Local Open Scope Z_scope. + +Local Definition mymap {A B} := Eval cbv in @List.map A B. +Local Definition myapp {A} := Eval cbv in @List.app A. +Local Definition myflatten {A} := Eval cbv in List.fold_right myapp (@nil A). +Local Notation dont_do_again := (pair false) (only parsing). +Local Notation do_again := (pair true) (only parsing). + +Import Language.Compilers. +Import LanguageWf.Compilers. + +Local Ltac start_proof := + cbv [snd]; hnf; cbv [PrimitiveHList.hlist ident.eagerly ident.literal ident.interp ident.fancy.interp ident.fancy.interp_with_wordmax Let_In ident.to_fancy invert_Some ident.cast2]; + repeat apply PrimitiveProd.Primitive.pair; try exact tt. + +Local Hint Resolve + eq_repeat_nat_rect + eq_app_list_rect + eq_combine_list_rect + eq_firstn_nat_rect + eq_skipn_nat_rect + eq_update_nth_nat_rect + : core. + +Lemma nbe_rewrite_rules_proofs + : PrimitiveHList.hlist (@snd bool Prop) nbe_rewrite_rulesT. +Proof using Type. start_proof; auto. Qed. + +Definition nbe_rewrite_rules_with_proofs + := Eval cbv [PrimitiveHList.combine_hlist nbe_rewrite_rulesT] in + PrimitiveHList.combine_hlist _ nbe_rewrite_rules_proofs. + +Local Ltac interp_good_t_step_related := + first [ lazymatch goal with + | [ |- ?x = ?x ] => reflexivity + | [ |- True ] => exact I + | [ H : ?x = true, H' : ?x = false |- _ ] => exfalso; clear -H H'; congruence + | [ |- ?G ] => has_evar G; reflexivity + | [ |- context[expr.interp_related_gen _ _ _ _] ] => reflexivity + | [ |- context[_ == _] ] => reflexivity + (*| [ |- context[(fst ?x, snd ?x)] ] => progress eta_expand + | [ |- context[match ?x with pair a b => _ end] ] => progress eta_expand*) + end + | progress cbn [fst snd] in * + | match goal with + | [ H : zrange * zrange |- _ ] => destruct H + end + | progress intros + | progress subst + | assumption + | progress inversion_option + | progress destruct_head'_and + | progress destruct_head'_unit + | progress split_andb + | match goal with + | [ H : ?x = ?x -> _ |- _ ] => specialize (H eq_refl) + | [ H : forall v : unit, _ |- _ ] => specialize (H tt) + | [ H : negb ?b = true |- _ ] => rewrite (@Bool.negb_true_iff b) in H + | [ |- context[Z.mul_split ?a ?b ?c] ] + => rewrite (surjective_pairing (Z.mul_split a b c)), Z.mul_split_div, Z.mul_split_mod + | [ |- context[Z.zselect] ] => rewrite Z.zselect_correct + | [ |- context[Z.sub_get_borrow_full ?a ?b ?c] ] + => rewrite (surjective_pairing (Z.sub_get_borrow_full a b c)), Z.sub_get_borrow_full_div, Z.sub_get_borrow_full_mod + | [ |- context[Z.sub_with_get_borrow_full ?a ?b ?c ?d] ] + => rewrite (surjective_pairing (Z.sub_with_get_borrow_full a b c d)), Z.sub_with_get_borrow_full_div, Z.sub_with_get_borrow_full_mod + | [ |- context[Z.add_get_carry_full ?a ?b ?c] ] + => rewrite (surjective_pairing (Z.add_get_carry_full a b c)), Z.add_get_carry_full_div, Z.add_get_carry_full_mod + | [ |- context[Z.add_with_get_carry_full ?a ?b ?c ?d] ] + => rewrite (surjective_pairing (Z.add_with_get_carry_full a b c d)), Z.add_with_get_carry_full_div, Z.add_with_get_carry_full_mod + | [ |- pair _ _ = pair _ _ ] => apply f_equal2 + | [ |- ?a mod ?b = ?a' mod ?b ] => apply f_equal2; lia + | [ |- ?a / ?b = ?a' / ?b ] => apply f_equal2; lia + | [ |- Z.opp _ = Z.opp _ ] => apply f_equal + end + | break_innermost_match_step + | break_innermost_match_hyps_step + | progress destruct_head'_or ]. + +Lemma arith_rewrite_rules_proofs (max_const_val : Z) + : PrimitiveHList.hlist (@snd bool Prop) (arith_rewrite_rulesT max_const_val). +Proof using Type. + start_proof; auto; intros; try lia. + all: autorewrite with zsimplify_const; try reflexivity. + all: repeat first [ reflexivity + | match goal with + | [ |- context[Z.shiftl] ] => rewrite Z.shiftl_mul_pow2 by auto with zarith + | [ |- context[Z.shiftr] ] => rewrite Z.shiftr_div_pow2 by auto with zarith + | [ H : ?x = 2^?n |- context[Z.land _ (?x - 1)] ] + => rewrite !Z.sub_1_r, H, <- Z.ones_equiv, Z.land_ones by auto with zarith + end + | Z.div_mod_to_quot_rem; nia + | interp_good_t_step_related ]. +Qed. + +Local Ltac interp_good_t_step_arith := + first [ lazymatch goal with + | [ |- ?x = ?x ] => reflexivity + | [ |- True ] => exact I + | [ H : ?x = true, H' : ?x = false |- _ ] => exfalso; clear -H H'; congruence + | [ H : true = false |- _ ]=> exfalso; clear -H; congruence + | [ H : false = true |- _ ]=> exfalso; clear -H; congruence + end + | progress cbv [option_beq] in * + | match goal with + | [ H : context[ZRange.normalize (ZRange.normalize _)] |- _ ] + => rewrite ZRange.normalize_idempotent in H + | [ |- context[ZRange.normalize (ZRange.normalize _)] ] + => rewrite ZRange.normalize_idempotent + | [ |- context[ident.cast (ZRange.normalize ?r)] ] + => rewrite ident.cast_normalize + | [ H : context[ident.cast (ZRange.normalize ?r)] |- _ ] + => rewrite ident.cast_normalize in H + | [ H : ?T, H' : ?T |- _ ] => clear H' + | [ H : context[is_bounded_by_bool _ (ZRange.normalize (-_))] |- _ ] + => rewrite ZRange.is_bounded_by_bool_move_opp_normalize in H + | [ |- context[is_bounded_by_bool _ (ZRange.normalize (-_))] ] + => rewrite ZRange.is_bounded_by_bool_move_opp_normalize + | [ H : is_bounded_by_bool ?v (ZRange.normalize ?r) = true |- context[ident.cast _ ?r ?v] ] + => rewrite (@ident.cast_in_normalized_bounds _ r v) by exact H + | [ H : is_bounded_by_bool ?v (ZRange.normalize ?r) = true |- context[ident.cast _ (-?r) (-?v)] ] + => rewrite (@ident.cast_in_normalized_bounds _ (-r) (-v)); + [ | clear -H ] + | [ |- context[ident.cast _ ?r (-ident.cast _ (-?r) ?v)] ] + => rewrite (ident.cast_in_normalized_bounds r (-ident.cast _ (-r) v)) + by (rewrite <- ZRange.is_bounded_by_bool_move_opp_normalize; apply ident.cast_always_bounded) + | [ |- context[ident.cast _ ?r (ident.cast _ ?r _)] ] + => rewrite (@ident.cast_idempotent _ _ r) + | [ H : is_bounded_by_bool _ ?r = true |- _] + => is_var r; unique pose proof (ZRange.is_bounded_by_normalize _ _ H) + | [ H : lower ?x = upper ?x |- _ ] => is_var x; destruct x; cbn [upper lower] in * + | [ H : is_bounded_by_bool ?x (ZRange.normalize r[?y~>?y]) = true |- _ ] + => apply ZRange.is_bounded_by_bool_normalize_constant_iff in H + | [ H : is_bounded_by_bool ?x r[?y~>?y] = true |- _ ] + => apply ZRange.is_bounded_by_bool_constant_iff in H + end + | progress intros + | progress subst + | assumption + | progress destruct_head'_and + | progress Z.ltb_to_lt + | progress split_andb + | match goal with + | [ |- ?a mod ?b = ?a' mod ?b ] => apply f_equal2; lia + | [ |- ?a / ?b = ?a' / ?b ] => apply f_equal2; lia + | [ |- Z.opp _ = Z.opp _ ] => apply f_equal + end + | break_innermost_match_step + | break_innermost_match_hyps_step + | progress destruct_head'_or + | match goal with + | [ |- context[-ident.cast _ (-?r) (-?v)] ] => rewrite (ident.cast_opp' r v) + | [ |- context[ident.cast ?coor ?r ?v] ] + => is_var v; + pose proof (@ident.cast_always_bounded coor r v); + generalize dependent (ident.cast coor r v); clear v; intro v; intros + | [ |- context[ident.cast ?coor ?r ?v] ] + => is_var v; is_var coor; + pose proof (@ident.cast_cases coor r v); + generalize dependent (ident.cast coor r v); intros + | [ H : is_bounded_by_bool ?v ?r = true, H' : is_tighter_than_bool ?r ?r' = true |- _ ] + => unique assert (is_bounded_by_bool v r' = true) by (eauto 2 using ZRange.is_bounded_by_of_is_tighter_than) + | [ H : is_bounded_by_bool (-?v) ?r = true, H' : (-?r <=? ?r')%zrange = true |- _ ] + => unique assert (is_bounded_by_bool v r' = true) + by (apply (@ZRange.is_bounded_by_of_is_tighter_than _ _ H'); + rewrite <- ZRange.is_bounded_by_bool_opp, ZRange.opp_involutive; exact H) + | [ H : is_bounded_by_bool ?v (-?r) = true |- _ ] + => is_var v; + unique assert (is_bounded_by_bool (-v) r = true) + by now rewrite <- ZRange.is_bounded_by_bool_move_opp_normalize, ZRange.normalize_opp + | [ H : is_bounded_by_bool ?x r[0~>?v-1] = true |- _ ] + => progress (try unique assert (0 <= x); try unique assert (x <= v - 1)); + [ clear -H; cbv [is_bounded_by_bool] in H; cbn [lower upper] in H; Bool.split_andb; Z.ltb_to_lt; lia.. + | ] + end + | progress cbn [expr.interp_related_gen] in * + | match goal with + | [ |- context[Z.shiftl] ] => rewrite Z.shiftl_mul_pow2 by auto with zarith + | [ |- context[Z.shiftr] ] => rewrite Z.shiftr_div_pow2 by auto with zarith + | [ |- context[Z.shiftl _ (-_)] ] => rewrite Z.shiftl_opp_r + | [ |- context[Z.land _ (Z.ones _)] ] => rewrite Z.land_ones by auto using Z.log2_nonneg + | [ |- context[- - _] ] => rewrite Z.opp_involutive + | [ H : ?x = 2^Z.log2 ?x |- context[2^Z.log2 ?x] ] => rewrite <- H + | [ H : ?x = 2^?n |- context[Z.land _ (?x - 1)] ] + => rewrite !Z.sub_1_r, H, <- Z.ones_equiv, Z.land_ones by auto with zarith + | [ |- _ = _ :> BinInt.Z ] => progress normalize_commutative_identifier Z.land Z.land_comm + | [ H : ?x = ?y, H' : ?x <> ?y |- _ ] => exfalso; apply H', H + | [ H : ?x = 2^Z.log2_up ?x - 1 |- context[2^Z.log2_up ?x - 1] ] => rewrite <- H + | [ H : ?x = 2^Z.log2 ?x, H' : context[2^Z.log2 ?x] |- _ = _ :> BinInt.Z ] + => rewrite <- H in H' + | [ |- _ = _ :> BinInt.Z ] => progress autorewrite with zsimplify_const + | [ H : 0 <= ?x, H' : ?x <= ?r - 1 |- context[?x mod ?r] ] + => rewrite (Z.mod_small x r) by (clear -H H'; lia) + | [ H : 0 <= ?x, H' : ?x <= ?y - 1 |- context[?x / ?y] ] + => rewrite (Z.div_small x y) by (clear -H H'; lia) + | [ H : ?x = 2^Z.log2 ?x |- _ ] + => unique assert (0 <= x) by (rewrite H; auto with zarith) + | [ |- _ mod ?x = _ mod ?x ] + => progress (push_Zmod; pull_Zmod) + | [ |- ?f (_ mod ?x) = ?f (_ mod ?x) ] + => progress (push_Zmod; pull_Zmod) + | [ |- _ mod ?x = _ mod ?x ] + => apply f_equal2; (lia + nia) + | _ => rewrite !Z.shiftl_mul_pow2 in * by auto using Z.log2_nonneg + | _ => rewrite !Z.land_ones in * by auto using Z.log2_nonneg + | H : ?x mod ?b * ?y <= _ + |- context [ (?x * ?y) mod ?b ] => + rewrite (PullPush.Z.mul_mod_l x y b); + rewrite (Z.mod_small (x mod b * y) b) by omega + | [ |- context[_ - ?x + ?x] ] => rewrite !Z.sub_add + | [ |- context[_ mod (2^_) * 2^_] ] => rewrite <- !Z.mul_mod_distr_r_full + | [ |- context[Z.land _ (Z.ones _)] ] => rewrite !Z.land_ones by lia + | [ |- context[2^?a * 2^?b] ] => rewrite <- !Z.pow_add_r by lia + | [ |- context[-?x + ?y] ] => rewrite !Z.add_opp_l + | [ |- context[?n + - ?m] ] => rewrite !Z.add_opp_r + | [ |- context[?n - - ?m] ] => rewrite !Z.sub_opp_r + | [ |- context[Zpos ?p * ?x / Zpos ?p] ] + => rewrite (@Z.div_mul' x (Zpos p)) in * by (clear; lia) + | [ H : context[Zpos ?p * ?x / Zpos ?p] |- _ ] + => rewrite (@Z.div_mul' x (Zpos p)) in * by (clear; lia) + | [ |- ?f (?a mod ?r) = ?f (?b mod ?r) ] => apply f_equal; apply f_equal2; lia + | [ |- context[-?a - ?b + ?c] ] => replace (-a - b + c) with (c - a - b) by (clear; lia) + | [ |- context[?x - ?y + ?z] ] + => lazymatch goal with + | [ |- context[z - y + x] ] + => progress replace (z - y + x) with (x - y + z) by (clear; lia) + end + | [ |- context[?x - ?y - ?z] ] + => lazymatch goal with + | [ |- context[x - z - y] ] + => progress replace (x - z - y) with (x - y - z) by (clear; lia) + end + | [ |- context[?x + ?y] ] + => lazymatch goal with + | [ |- context[y + x] ] + => progress replace (y + x) with (x + y) by (clear; lia) + end + | [ |- context[?x + ?y + ?z] ] + => lazymatch goal with + | [ |- context[x + z + y] ] + => progress replace (x + z + y) with (x + y + z) by (clear; lia) + | [ |- context[z + x + y] ] + => progress replace (z + x + y) with (x + y + z) by (clear; lia) + | [ |- context[z + y + x] ] + => progress replace (z + y + x) with (x + y + z) by (clear; lia) + | [ |- context[y + x + z] ] + => progress replace (y + x + z) with (x + y + z) by (clear; lia) + | [ |- context[y + z + x] ] + => progress replace (y + z + x) with (x + y + z) by (clear; lia) + end + | [ |- - ident.cast _ (-?r) (- (?x / ?y)) = ident.cast _ ?r (?x' / ?y) ] + => tryif constr_eq x x' then fail else replace x with x' by lia + | [ |- _ = _ :> BinInt.Z ] => progress autorewrite with zsimplify_fast + end ]. + +Local Ltac remove_casts := + repeat match goal with + | [ |- context[ident.cast _ r[?x~>?x] ?x] ] + => rewrite (ident.cast_in_bounds r[x~>x] x) by apply ZRange.is_bounded_by_bool_constant + | [ |- context[ident.cast _ ?r (ident.cast _ ?r _)] ] + => rewrite ident.cast_idempotent + | [ H : context[ident.cast _ ?r (ident.cast _ ?r _)] |- _ ] + => rewrite ident.cast_idempotent in H + | [ |- context[ident.cast ?coor ?r ?v] ] + => is_var v; + pose proof (@ident.cast_always_bounded coor r v); + generalize dependent (ident.cast coor r v); + clear v; intro v; intros + | [ H : context[ident.cast ?coor ?r ?v] |- _ ] + => is_var v; + pose proof (@ident.cast_always_bounded coor r v); + generalize dependent (ident.cast coor r v); + clear v; intro v; intros + | [ H : context[ZRange.constant ?v] |- _ ] => unique pose proof (ZRange.is_bounded_by_bool_normalize_constant v) + | [ H : is_tighter_than_bool (?ZRf ?r1 ?r2) (ZRange.normalize ?rs) = true, + H1 : is_bounded_by_bool ?v1 ?r1 = true, + H2 : is_bounded_by_bool ?v2 ?r2 = true + |- _ ] + => let cst := multimatch goal with + | [ |- context[ident.cast ?coor rs (?Zf v1 v2)] ] => constr:(ident.cast coor rs (Zf v1 v2)) + | [ H : context[ident.cast ?coor rs (?Zf v1 v2)] |- _ ] => constr:(ident.cast coor rs (Zf v1 v2)) + end in + lazymatch cst with + | ident.cast ?coor rs (?Zf v1 v2) + => let lem := lazymatch constr:((ZRf, Zf)%core) with + | (ZRange.shiftl, Z.shiftl)%core => constr:(@ZRange.is_bounded_by_bool_shiftl v1 r1 v2 r2 H1 H2) + | (ZRange.shiftr, Z.shiftr)%core => constr:(@ZRange.is_bounded_by_bool_shiftr v1 r1 v2 r2 H1 H2) + | (ZRange.land, Z.land)%core => constr:(@ZRange.is_bounded_by_bool_land v1 r1 v2 r2 H1 H2) + end in + try unique pose proof (@ZRange.is_bounded_by_of_is_tighter_than _ _ H _ lem); + clear H; + rewrite (@ident.cast_in_normalized_bounds coor rs (Zf v1 v2)) in * by assumption + end + | [ H : is_tighter_than_bool (?ZRf ?r1) (ZRange.normalize ?rs) = true, + H1 : is_bounded_by_bool ?v1 ?r1 = true + |- _ ] + => let cst := multimatch goal with + | [ |- context[ident.cast ?coor rs (?Zf v1)] ] => constr:(ident.cast coor rs (Zf v1)) + | [ H : context[ident.cast ?coor rs (?Zf v1)] |- _ ] => constr:(ident.cast coor rs (Zf v1)) + end in + lazymatch cst with + | ident.cast ?coor rs (?Zf v1) + => let lem := lazymatch constr:((ZRf, Zf)%core) with + | (ZRange.cc_m ?s, Z.cc_m ?s)%core => constr:(@ZRange.is_bounded_by_bool_cc_m s v1 r1 H1) + end in + try unique pose proof (@ZRange.is_bounded_by_of_is_tighter_than _ _ H _ lem); + clear H; + rewrite (@ident.cast_in_normalized_bounds coor rs (Zf v1)) in * by assumption + end + | [ H : is_bounded_by_bool ?v (ZRange.normalize ?r) = true |- context[ident.cast ?coor ?r ?v] ] + => rewrite (@ident.cast_in_normalized_bounds coor r v) in * by assumption + | [ H : is_bounded_by_bool ?v (ZRange.normalize ?r) = true, H' : context[ident.cast ?coor ?r ?v] |- _ ] + => rewrite (@ident.cast_in_normalized_bounds coor r v) in * by assumption + | [ H : is_bounded_by_bool ?v ?r = true, + H' : is_tighter_than_bool ?r r[0~>?x-1]%zrange = true, + H'' : Z.eqb ?x ?m = true + |- context[?v mod ?m] ] + => unique assert (is_bounded_by_bool v r[0~>x-1] = true) + by (eapply ZRange.is_bounded_by_of_is_tighter_than; eassumption) + | _ => progress Z.ltb_to_lt + | _ => progress subst + end. + +Local Lemma unfold_is_bounded_by_bool v r + : is_bounded_by_bool v r = true -> lower r <= v <= upper r. +Proof using Type. + cbv [is_bounded_by_bool]; intro; split_andb; Z.ltb_to_lt; split; assumption. +Qed. + +Local Lemma unfold_is_tighter_than_bool r1 r2 + : is_tighter_than_bool r1 r2 = true -> lower r2 <= lower r1 /\ upper r1 <= upper r2. +Proof using Type. + cbv [is_tighter_than_bool]; intro; split_andb; Z.ltb_to_lt; split; assumption. +Qed. + +Local Ltac unfold_cast_lemmas := + repeat match goal with + | [ H : context[ZRange.normalize (ZRange.constant _)] |- _ ] + => rewrite ZRange.normalize_constant in H + | [ H : is_bounded_by_bool _ (ZRange.normalize ?r) = true |- _ ] + => is_var r; generalize dependent (ZRange.normalize r); clear r; intro r; intros + | [ H : is_bounded_by_bool ?x (ZRange.constant ?x) = true |- _ ] + => clear H + | [ H : is_bounded_by_bool ?x ?r = true |- _ ] + => is_var r; apply unfold_is_bounded_by_bool in H + | [ H : is_bounded_by_bool ?x r[_~>_] = true |- _ ] + => apply unfold_is_bounded_by_bool in H + | [ H : is_tighter_than_bool r[_~>_] r[_~>_] = true |- _ ] + => apply unfold_is_tighter_than_bool in H + | _ => progress cbn [lower upper] in * + | [ H : context[lower ?r] |- _ ] + => is_var r; let l := fresh "l" in let u := fresh "u" in destruct r as [l u] + | [ H : context[upper ?r] |- _ ] + => is_var r; let l := fresh "l" in let u := fresh "u" in destruct r as [l u] + | _ => progress Z.ltb_to_lt + end. + +Local Ltac clear_useless_hyps := + repeat match goal with + | [ H : True |- _ ] => clear H + | [ H : unit |- _ ] => clear H + | [ H : nat |- _ ] => clear H + | [ H : Z |- _ ] => clear H + | [ H : zrange |- _ ] => clear H + | [ H : ?x = ?x |- _ ] => clear H + | [ H : ?x <= ?y <= ?z |- _ ] + => is_var x; is_var z; clear x z H + | [ H : ?x <= ?x' /\ ?y' <= ?y, H' : ?x' <= ?z <= ?y' |- _ ] + => is_var x'; is_var y'; + let H'' := fresh in + assert (H'' : x <= z <= y) by (clear -H H'; lia); + clear x' y' H H' + end. + +Local Ltac systematically_handle_casts := + remove_casts; unfold_cast_lemmas; clear_useless_hyps. + + +Local Ltac fin_with_nia := + lazymatch goal with + | [ |- ident.cast _ ?r _ = ident.cast _ ?r _ ] => apply f_equal; Z.div_mod_to_quot_rem; nia + | _ => reflexivity || (Z.div_mod_to_quot_rem; (lia + nia)) + end. + +Lemma arith_with_casts_rewrite_rules_proofs + : PrimitiveHList.hlist (@snd bool Prop) arith_with_casts_rewrite_rulesT. +Proof using Type. + start_proof; auto; intros; try lia. + all: repeat interp_good_t_step_related. + all: repeat interp_good_t_step_arith. + all: remove_casts; try fin_with_nia. +Qed. + +Lemma strip_literal_casts_rewrite_rules_proofs + : PrimitiveHList.hlist (@snd bool Prop) strip_literal_casts_rewrite_rulesT. +Proof using Type. + start_proof; auto; intros; remove_casts; reflexivity. +Qed. + +Section fancy. + Context (invert_low invert_high : Z (*log2wordmax*) -> Z -> option Z) + (value_range flag_range : zrange). + + Lemma fancy_rewrite_rules_proofs + : PrimitiveHList.hlist (@snd bool Prop) fancy_rewrite_rulesT. + Proof using Type. start_proof. Qed. + + Local Ltac fancy_local_t := + repeat match goal with + | [ H : forall s v v', ?invert_low s v = Some v' -> v = _, + H' : ?invert_low _ _ = Some _ |- _ ] => apply H in H' + | [ H : forall s v v', ?invert_low s v = Some v' -> v = _ |- _ ] + => clear invert_low H + | [ H : None <> None |- _ ] => exfalso; exact (H eq_refl) + end. + Local Ltac more_fancy_arith_t := repeat autorewrite with zsimplify in *. + + Lemma fancy_with_casts_rewrite_rules_proofs + (Hlow : forall s v v', invert_low s v = Some v' -> v = Z.land v' (2^(s/2)-1)) + (Hhigh : forall s v v', invert_high s v = Some v' -> v = Z.shiftr v' (s/2)) + : PrimitiveHList.hlist (@snd bool Prop) (@fancy_with_casts_rewrite_rulesT invert_low invert_high value_range flag_range). + Proof using Type. + start_proof; auto; intros; try lia. + Time all: repeat interp_good_t_step_related. + Time all: fancy_local_t. + Time all: try solve [ systematically_handle_casts; repeat interp_good_t_step_arith ]. + Qed. +End fancy. -- cgit v1.2.3