|
1 |
| -Require Import Coq.ZArith.BinIntDef Coq.ZArith.BinInt coqutil.Z.Lia. |
| 1 | +From Coq Require Import BinInt Zmod Bits. |
2 | 2 | Require Import coqutil.Tactics.destr.
|
3 | 3 | Require Import coqutil.sanity coqutil.Word.Interface. Import word.
|
4 | 4 | Local Open Scope Z_scope.
|
5 | 5 |
|
6 |
| -(* TODO: move me? *) |
7 |
| -Definition minimize_eq_proof{A: Type}(eq_dec: forall (x y: A), {x = y} + {x <> y}){x y: A} (pf: x = y): x = y := |
8 |
| - match eq_dec x y with |
9 |
| - | left p => p |
10 |
| - | right n => match n pf: False with end |
11 |
| - end. |
12 |
| - |
13 | 6 | Section WithWidth. Local Set Default Proof Using "All".
|
14 | 7 | Context {width : Z}.
|
| 8 | + Definition rep : Set := bits width. |
| 9 | + Definition unsigned (w : rep) := Zmod.unsigned w. |
| 10 | + |
| 11 | + Definition wrap (z:Z) : rep := bits.of_Z width z. |
| 12 | + Definition signed (w : rep) := Zmod.signed w. |
| 13 | + |
15 | 14 | Let wrap_value z := z mod (2^width).
|
16 | 15 | Let swrap_value z := wrap_value (z + 2 ^ (width - 1)) - 2 ^ (width - 1).
|
17 |
| - Record rep : Set := mk { unsigned : Z ; _unsigned_in_range : wrap_value unsigned = unsigned }. |
18 |
| - |
19 |
| - Definition wrap (z:Z) : rep := |
20 |
| - mk (wrap_value z) (minimize_eq_proof Z.eq_dec (Zdiv.Zmod_mod z _)). |
21 |
| - Definition signed w := swrap_value (unsigned w). |
22 | 16 |
|
23 | 17 | Record special_cases : Set := {
|
24 |
| - div_by_zero: Z -> Z; |
25 |
| - mod_by_zero: Z -> Z; |
26 | 18 | adjust_too_big_shift_amount: Z -> Z;
|
27 | 19 | }.
|
28 | 20 |
|
@@ -50,81 +42,113 @@ Section WithWidth. Local Set Default Proof Using "All".
|
50 | 42 | word.signed := signed;
|
51 | 43 | of_Z := wrap;
|
52 | 44 |
|
53 |
| - add x y := wrap (Z.add (unsigned x) (unsigned y)); |
54 |
| - sub x y := wrap (Z.sub (unsigned x) (unsigned y)); |
55 |
| - opp x := wrap (Z.opp (unsigned x)); |
| 45 | + add := Zmod.add; |
| 46 | + sub := Zmod.sub; |
| 47 | + opp := Zmod.opp; |
56 | 48 |
|
57 |
| - or x y := wrap (Z.lor (unsigned x) (unsigned y)); |
58 |
| - and x y := wrap (Z.land (unsigned x) (unsigned y)); |
59 |
| - xor x y := wrap (Z.lxor (unsigned x) (unsigned y)); |
60 |
| - not x := wrap (Z.lnot (unsigned x)); |
61 |
| - ndn x y := wrap (Z.ldiff (unsigned x) (unsigned y)); |
| 49 | + or := Zmod.or; |
| 50 | + and := Zmod.and; |
| 51 | + xor := Zmod.xor; |
| 52 | + not := Zmod.not; |
| 53 | + ndn := Zmod.ndn; |
62 | 54 |
|
63 |
| - mul x y := wrap (Z.mul (unsigned x) (unsigned y)); |
| 55 | + mul := Zmod.mul; |
64 | 56 | mulhss x y := wrap (Z.mul (signed x) (signed y) / 2^width);
|
65 | 57 | mulhsu x y := wrap (Z.mul (signed x) (unsigned y) / 2^width);
|
66 | 58 | mulhuu x y := wrap (Z.mul (unsigned x) (unsigned y) / 2^width);
|
67 | 59 |
|
68 |
| - divu x y := wrap (if Z.eqb (unsigned y) 0 then sp.(div_by_zero) (unsigned x) |
69 |
| - else Z.div (unsigned x) (unsigned y)); |
70 |
| - divs x y := wrap (if Z.eqb (signed y) 0 then sp.(div_by_zero) (signed x) |
71 |
| - else Z.quot (signed x) (signed y)); |
72 |
| - modu x y := wrap (if Z.eqb (unsigned y) 0 then sp.(mod_by_zero) (unsigned x) |
73 |
| - else Z.modulo (unsigned x) (unsigned y)); |
74 |
| - mods x y := wrap (if Z.eqb (signed y) 0 then sp.(mod_by_zero) (signed x) |
75 |
| - else Z.rem (signed x) (signed y)); |
| 60 | + divu := Zmod.udiv; |
| 61 | + divs := Zmod.squot; |
| 62 | + modu := Zmod.umod; |
| 63 | + mods := Zmod.srem; |
76 | 64 |
|
77 |
| - slu x y := wrap (Z.shiftl (unsigned x) (adjust_shift_amount (unsigned y))); |
78 |
| - sru x y := wrap (Z.shiftr (unsigned x) (adjust_shift_amount (unsigned y))); |
79 |
| - srs x y := wrap (Z.shiftr (signed x) (adjust_shift_amount (unsigned y))); |
| 65 | + slu x y := Zmod.slu x (adjust_shift_amount (unsigned y)); |
| 66 | + sru x y := Zmod.sru x (adjust_shift_amount (unsigned y)); |
| 67 | + srs x y := Zmod.srs x (adjust_shift_amount (unsigned y)); |
80 | 68 |
|
81 |
| - eqb x y := Z.eqb (unsigned x) (unsigned y); |
| 69 | + eqb := Zmod.eqb; |
82 | 70 | ltu x y := Z.ltb (unsigned x) (unsigned y);
|
83 | 71 | lts x y := Z.ltb (signed x) (signed y);
|
84 | 72 |
|
85 | 73 | sextend oldwidth z := wrap ((unsigned z + 2^(oldwidth-1)) mod 2^oldwidth - 2^(oldwidth-1));
|
86 | 74 | |}.
|
87 | 75 |
|
88 | 76 | Lemma eq_unsigned {x y : rep} : unsigned x = unsigned y -> x = y.
|
89 |
| - Proof. |
90 |
| - cbv [value]; destruct x as [x px], y as [y py]; cbn. |
91 |
| - intro; subst y. |
92 |
| - apply f_equal, Eqdep_dec.UIP_dec. eapply Z.eq_dec. |
93 |
| - Qed. |
| 77 | + Proof. apply Zmod.unsigned_inj. Qed. |
94 | 78 |
|
95 | 79 | Lemma of_Z_unsigned x : wrap (unsigned x) = x.
|
96 |
| - Proof. eapply eq_unsigned; destruct x; cbn; assumption. Qed. |
| 80 | + Proof. apply Zmod.of_Z_to_Z. Qed. |
| 81 | + |
| 82 | + (* Candidate for stdlib inclusion: *) |
| 83 | + Lemma smod_swrap z : ZModOffset.Z.smodulo z (2 ^ width) = @swrap width gen_word z. |
| 84 | + Proof. |
| 85 | + cbv [swrap gen_word]. |
| 86 | + cbv [ZModOffset.Z.smodulo ZModOffset.Z.omodulo]. |
| 87 | + rewrite Z.add_opp_r, Z.sub_opp_r. |
| 88 | + case (Z.eqb_spec width 0) as [->|]; trivial. |
| 89 | + case (Z.eqb_spec width 1) as [->|]; trivial. |
| 90 | + case (Z.ltb_spec width 0) as []. { rewrite !Z.pow_neg_r by lia; trivial. } |
| 91 | + rewrite Z.pow_sub_r by try lia; change (2^1) with 2. |
| 92 | + rewrite Z.quot_div_nonneg by lia; trivial. |
| 93 | + Qed. |
97 | 94 |
|
98 | 95 | Lemma signed_of_Z z : signed (wrap z) = wrap_value (z + 2 ^ (width - 1)) - 2 ^ (width - 1).
|
99 | 96 | Proof.
|
| 97 | + cbv [signed wrap]; rewrite Zmod.signed_of_Z. |
100 | 98 | cbv [unsigned signed wrap wrap_value swrap_value].
|
101 |
| - rewrite Zdiv.Zplus_mod_idemp_l; auto. |
| 99 | + apply smod_swrap. |
102 | 100 | Qed.
|
103 | 101 |
|
104 | 102 | Context (width_nonneg : Z.lt 0 width).
|
105 | 103 |
|
106 | 104 | Global Instance gen_ok : word.ok gen_word.
|
107 | 105 | Proof.
|
108 |
| - split; intros; |
109 |
| - repeat match goal with |
110 |
| - | a: @word.rep _ _ |- _ => destruct a |
111 |
| - end; |
112 |
| - cbn in *; |
113 |
| - unfold adjust_shift_amount in *; |
114 |
| - repeat match goal with |
115 |
| - | |- context[if ?b then _ else _] => destr b |
116 |
| - end; |
117 |
| - eauto using of_Z_unsigned, signed_of_Z; |
118 |
| - try (exfalso; blia). |
119 |
| - apply eq_unsigned; assumption. |
| 106 | + split; trivial; |
| 107 | + cbv [gen_word adjust_shift_amount signed unsigned wrap]; intros. |
| 108 | + { apply Zmod.unsigned_of_Z. } |
| 109 | + { rewrite <-smod_swrap. apply Zmod.signed_of_Z. } |
| 110 | + { apply Zmod.of_Z_to_Z. } |
| 111 | + { apply Zmod.unsigned_add. } |
| 112 | + { apply Zmod.unsigned_sub. } |
| 113 | + { apply Zmod.unsigned_opp. } |
| 114 | + { apply Zmod.unsigned_of_Z. } |
| 115 | + { apply Zmod.unsigned_of_Z. } |
| 116 | + { apply Zmod.unsigned_of_Z. } |
| 117 | + { apply Zmod.unsigned_of_Z. } |
| 118 | + { apply Zmod.unsigned_of_Z. } |
| 119 | + { apply Zmod.unsigned_mul. } |
| 120 | + { cbv [word.signed mulhss]. rewrite Zmod.signed_of_Z, smod_swrap; trivial. } |
| 121 | + { cbv [word.signed mulhsu]. rewrite Zmod.signed_of_Z, smod_swrap; trivial. } |
| 122 | + { cbv [word.unsigned mulhuu]. apply Zmod.unsigned_of_Z. } |
| 123 | + { cbv [word.unsigned divu]. rewrite Zmod.unsigned_udiv; trivial. } |
| 124 | + { cbv [word.signed divs]. rewrite Zmod.signed_squot, <-smod_swrap. |
| 125 | + case Z.eqb_spec; [contradiction|]; trivial. } |
| 126 | + { cbv [word.unsigned modu] in *. rewrite Zmod.unsigned_umod; trivial. |
| 127 | + symmetry; apply Z.mod_small. |
| 128 | + pose proof Zmod.unsigned_pos_bound x ltac:(lia). |
| 129 | + pose proof Zmod.unsigned_pos_bound y ltac:(lia). |
| 130 | + pose proof (Z.mod_pos_bound (Zmod.unsigned x) (Zmod.unsigned y)). |
| 131 | + lia. } |
| 132 | + { cbv [word.signed mods]. rewrite Zmod.signed_srem, <-smod_swrap; trivial. } |
| 133 | + { cbv [word.unsigned slu] in *; case Z.ltb_spec; intros; [|lia]. |
| 134 | + apply Zmod.unsigned_slu. } |
| 135 | + { cbv [word.unsigned sru] in *; case Z.ltb_spec; intros; [|lia]. |
| 136 | + pose proof Zmod.unsigned_pos_bound x ltac:(lia). |
| 137 | + pose proof Zmod.unsigned_pos_bound y ltac:(lia). |
| 138 | + rewrite Zmod.unsigned_sru, Z.mod_small; |
| 139 | + rewrite ?Z.shiftr_div_pow2; try (Z.to_euclidean_division_equations; nia). } |
| 140 | + { cbv [word.unsigned word.signed srs] in *; case Z.ltb_spec; intros; [|lia]. |
| 141 | + pose proof Zmod.signed_pos_bound x ltac:(lia). |
| 142 | + pose proof Zmod.unsigned_pos_bound y ltac:(lia). |
| 143 | + rewrite Zmod.signed_srs, <-smod_swrap, Z.smod_even_small; |
| 144 | + rewrite ?Z.shiftr_div_pow2; try (Z.to_euclidean_division_equations; nia). |
| 145 | + rewrite <-(Z.succ_pred width), Z.pow_succ_r, Z.mul_comm, Z.rem_mul; lia. } |
120 | 146 | Qed.
|
121 | 147 | End WithWidth.
|
122 | 148 | Arguments gen_word : clear implicits.
|
123 | 149 | Arguments gen_ok : clear implicits.
|
124 | 150 |
|
125 | 151 | Definition default_special_case_handlers width := {|
|
126 |
| - div_by_zero x := -1; |
127 |
| - mod_by_zero x := x; |
128 | 152 | adjust_too_big_shift_amount n := n mod 2 ^ Z.log2 width;
|
129 | 153 | |}.
|
130 | 154 |
|
|
0 commit comments