diff --git a/src/Init/Data/BitVec/Bitblast.lean b/src/Init/Data/BitVec/Bitblast.lean index 7f42fa8e4e..2582562152 100644 --- a/src/Init/Data/BitVec/Bitblast.lean +++ b/src/Init/Data/BitVec/Bitblast.lean @@ -1930,6 +1930,44 @@ theorem toInt_sub_neg_umod {x y : BitVec w} (hxmsb : x.msb = true) (hymsb : y.ms Int.dvd_neg] at hdvd simp only [hdvd, ↓reduceIte, Int.natAbs_cast] +theorem srem_zero_of_dvd {x y : BitVec w} (h : y.toInt ∣ x.toInt) : + x.srem y = 0#w := by + have := toInt_dvd_toInt_iff (x := x) (y := y) + by_cases hx : x.msb <;> by_cases hy : y.msb + <;> simp only [h, hx, reduceIte, hy, false_eq_true, true_iff] at this + <;> simp [srem, hx, hy, this] + +/-- +The remainder for `srem`, i.e. division with rounding to zero is negative +iff `x` is negative and `y` does not divide `x`. + +We can eventually build fast circuits for the divisibility test `x.srem y = 0`. +-/ +theorem msb_srem {x y : BitVec w} : (x.srem y).msb = + (x.msb && decide (x.srem y ≠ 0)) := by + rw [msb_eq_toInt] + by_cases hx : x.msb + · by_cases hsrem : x.srem y = 0#w + · simp [hsrem] + · have := toInt_neg_of_msb_true hx + by_cases hdvd : y.toInt ∣ x.toInt + · simp [BitVec.srem_zero_of_dvd hdvd] at hsrem + · simp only [toInt_srem, Int.tmod_eq_emod, show ¬0 ≤ x.toInt by omega, hdvd, _root_.or_self, + reduceIte, hx, ofNat_eq_ofNat, ne_eq, hsrem, not_false_eq_true, decide_true, Bool.and_self, + decide_eq_true_eq, gt_iff_lt] + have hlt := Int.emod_lt (a := x.toInt) (b := y.toInt) + by_cases hy0 : y = 0#w + · simp only [hy0, toInt_zero, Int.emod_zero, Int.natAbs_zero, Int.cast_ofNat_Int, + Int.sub_zero, gt_iff_lt] + exact toInt_neg_of_msb_true hx + · simp only [← toInt_inj, toInt_zero] at hy0 + simp only [ne_eq, hy0, not_false_eq_true, forall_const] at hlt + have := Int.le_natAbs (a := y.toInt) + omega + · simp only [toInt_srem, hx, ofNat_eq_ofNat, ne_eq, decide_not, Bool.false_and, + decide_eq_false_iff_not, Int.not_lt] + apply Int.tmod_nonneg y.toInt (by exact toInt_nonneg_of_msb_false (by simp at hx; exact hx)) + theorem toInt_smod {x y : BitVec w} : (x.smod y).toInt = x.toInt.fmod y.toInt := by rcases w with _|w @@ -1998,6 +2036,30 @@ theorem getMsbD_smod {x y : BitVec w} : by_cases hx : x.msb <;> by_cases hy : y.msb <;> simp [hx, hy] +theorem msb_smod {x y : BitVec w} : + (x.smod y).msb = (x.msb && y = 0) || (y.msb && (x.smod y) ≠ 0) := by + rw [msb_eq_toInt] + by_cases hx : x.msb <;> by_cases hy : y.msb + · by_cases hsmod : x.smod y = 0#w <;> simp [hx, hy, hsmod] + · simp only [hx, ofNat_eq_ofNat, Bool.true_and, decide_eq_decide, decide_iff_dist, hy, ne_eq, + decide_not, Bool.false_and, Bool.or_false, beq_iff_eq] + constructor + · intro h + apply Classical.byContradiction + intro hcontra + rw [toInt_smod] at h + have := toInt_nonneg_of_msb_false (by simp at hy; exact hy) + have := Int.fmod_nonneg_of_pos (a := x.toInt) (b := y.toInt) (by simp [← toInt_inj] at hcontra; omega) + omega + · intro h + simp only [h, smod_zero] + exact toInt_neg_of_msb_true hx + · by_cases hsmod : x.smod y = 0#w <;> simp [hx, hy, hsmod] + · simp only [toInt_smod, hx, ofNat_eq_ofNat, Bool.false_and, decide_eq_false_iff_not, Int.not_lt, + hy, ne_eq, decide_not, Bool.or_false, decide_eq_true_eq] + simp only [not_eq_true] at hx hy + apply Int.fmod_nonneg (by exact toInt_nonneg_of_msb_false hx) (by exact toInt_nonneg_of_msb_false hy) + /-! ### Lemmas that use bit blasting circuits -/ theorem add_sub_comm {x y : BitVec w} : x + y - z = x - z + y := by