Section Z_DIV_MUL.
Variable N: Z.      (**r number of relevant bits *)
Hypothesis N_pos: N >= 0.
Variable d: Z.      (**r divisor *)
Hypothesis d_pos: d > 0.
(** This is theorem 4.2 from Granlund and Montgomery, PLDI 1994. *)
(** This is theorem 5.1 from Granlund and Montgomery, PLDI 1994. *)
End Z_DIV_MUL.
(** * Correctness of the division parameters *)
Proof with (try discriminate).
unfold divs_mul_params; intros d m' p'.
destruct (find_div_mul_params Int.wordsize
(Int.half_modulus - Int.half_modulus mod d - 1) d 32)
as [[p m] | ]...
generalize (p - 32). intro p1.
destruct (zlt 0 d)...
destruct (zlt (two_p (32 + p1)) (m * d))...
destruct (zle (m * d) (two_p (32 + p1) + two_p (p1 + 1)))...
destruct (zle 0 m)...
destruct (zlt m Int.modulus)...
destruct (zle 0 p1)...
destruct (zlt p1 32)...
intros EQ; inv EQ.
split. auto. split. auto. intros.
replace (32 + p') with (31 + (p' + 1)) by omega.
apply Zquot_mul; try omega.
replace (31 + (p' + 1)) with (32 + p') by omega. omega.
change (Int.min_signed <= n < Int.half_modulus).
unfold Int.max_signed in H. omega.
Qed.
Proof with (try discriminate).
unfold divu_mul_params; intros d m' p'.
destruct (find_div_mul_params Int.wordsize
(Int.modulus - Int.modulus mod d - 1) d 32)
as [[p m] | ]...
generalize (p - 32); intro p1.
destruct (zlt 0 d)...
destruct (zle (two_p (32 + p1)) (m * d))...
destruct (zle (m * d) (two_p (32 + p1) + two_p p1))...
destruct (zle 0 m)...
destruct (zlt m Int.modulus)...
destruct (zle 0 p1)...
destruct (zlt p1 32)...
intros EQ; inv EQ.
split. auto. split. auto. intros.
apply Zdiv_mul_pos; try omega. assumption.
Qed.
(** Same, for 64-bit integers *)
Proof with (try discriminate).
unfold divls_mul_params; intros d m' p'.
destruct (find_div_mul_params Int64.wordsize
(Int64.half_modulus - Int64.half_modulus mod d - 1) d 64)
as [[p m] | ]...
generalize (p - 64). intro p1.
destruct (zlt 0 d)...
destruct (zlt (two_p (64 + p1)) (m * d))...
destruct (zle (m * d) (two_p (64 + p1) + two_p (p1 + 1)))...
destruct (zle 0 m)...
destruct (zlt m Int64.modulus)...
destruct (zle 0 p1)...
destruct (zlt p1 64)...
intros EQ; inv EQ.
split. auto. split. auto. intros.
replace (64 + p') with (63 + (p' + 1)) by omega.
apply Zquot_mul; try omega.
replace (63 + (p' + 1)) with (64 + p') by omega. omega.
change (Int64.min_signed <= n < Int64.half_modulus).
unfold Int64.max_signed in H. omega.
Qed.

Lemma divlu_mul_params_sound:
forall d m p,
divlu_mul_params d = Some(p, m) ->
0 <= m < Int64.modulus /\ 0 <= p < 64 /\
forall n,
0 <= n < Int64.modulus ->
Z.div n d = Z.div (m * n) (two_p (64 + p)).