Skip to content

Commit 8c7f748

Browse files
authored
feat: if support and more in bv_decide (leanprover#5855)
Using the same strategy as leanprover#5852 this provides `bv_decide` support for `Bool` and `BitVec` ifs this in turn instantly enables support for: - `sdiv` - `smod` - `abs` and thus closes our last discrepancies to QF_BV!
1 parent c50f04a commit 8c7f748

File tree

21 files changed

+227
-537
lines changed

21 files changed

+227
-537
lines changed

src/Init/Data/BitVec/Lemmas.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,8 @@ theorem not_neg (x : BitVec w) : ~~~(-x) = x + -1#w := by
21152115

21162116
/-! ### abs -/
21172117

2118+
theorem abs_eq (x : BitVec w) : x.abs = if x.msb then -x else x := by rfl
2119+
21182120
@[simp, bv_toNat]
21192121
theorem toNat_abs {x : BitVec w} : x.abs.toNat = if x.msb then 2^w - x.toNat else x.toNat := by
21202122
simp only [BitVec.abs, neg_eq]

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide/Reflect.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ instance : ToExpr BVBinOp where
2929
| .mul => mkConst ``BVBinOp.mul
3030
| .udiv => mkConst ``BVBinOp.udiv
3131
| .umod => mkConst ``BVBinOp.umod
32-
| .sdiv => mkConst ``BVBinOp.sdiv
3332
toTypeExpr := mkConst ``BVBinOp
3433

3534
instance : ToExpr BVUnOp where
@@ -103,6 +102,7 @@ where
103102
| .const b => mkApp2 (mkConst ``BoolExpr.const) (toTypeExpr α) (toExpr b)
104103
| .not x => mkApp2 (mkConst ``BoolExpr.not) (toTypeExpr α) (go x)
105104
| .gate g x y => mkApp4 (mkConst ``BoolExpr.gate) (toTypeExpr α) (toExpr g) (go x) (go y)
105+
| .ite d l r => mkApp4 (mkConst ``BoolExpr.ite) (toTypeExpr α) (go d) (go l) (go r)
106106

107107

108108
open Lean.Meta

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide/ReifiedBVLogical.lean

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ Construct the reified version of applying the gate in `gate` to `lhs` and `rhs`.
5757
This function assumes that `lhsExpr` and `rhsExpr` are the corresponding expressions to `lhs`
5858
and `rhs`.
5959
-/
60-
def mkGate (lhs rhs : ReifiedBVLogical) (lhsExpr rhsExpr : Expr) (gate : Gate) : M ReifiedBVLogical := do
60+
def mkGate (lhs rhs : ReifiedBVLogical) (lhsExpr rhsExpr : Expr) (gate : Gate) :
61+
M ReifiedBVLogical := do
6162
let congrThm := congrThmOfGate gate
6263
let boolExpr := .gate gate lhs.bvExpr rhs.bvExpr
6364
let expr :=
@@ -99,6 +100,35 @@ def mkNot (sub : ReifiedBVLogical) (subExpr : Expr) : M ReifiedBVLogical := do
99100
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
100101
return ⟨boolExpr, proof, expr⟩
101102

103+
/--
104+
Construct the reified version of `if discrExpr then lhsExpr else rhsExpr`.
105+
This function assumes that `discrExpr`, lhsExpr` and `rhsExpr` are the corresponding expressions to
106+
`discr`, `lhs` and `rhs`.
107+
-/
108+
def mkIte (discr lhs rhs : ReifiedBVLogical) (discrExpr lhsExpr rhsExpr : Expr) :
109+
M ReifiedBVLogical := do
110+
let boolExpr := .ite discr.bvExpr lhs.bvExpr rhs.bvExpr
111+
let expr :=
112+
mkApp4
113+
(mkConst ``BoolExpr.ite)
114+
(mkConst ``BVPred)
115+
discr.expr
116+
lhs.expr
117+
rhs.expr
118+
let proof := do
119+
let discrEvalExpr ← ReifiedBVLogical.mkEvalExpr discr.expr
120+
let lhsEvalExpr ← ReifiedBVLogical.mkEvalExpr lhs.expr
121+
let rhsEvalExpr ← ReifiedBVLogical.mkEvalExpr rhs.expr
122+
let discrProof ← discr.evalsAtAtoms
123+
let lhsProof ← lhs.evalsAtAtoms
124+
let rhsProof ← rhs.evalsAtAtoms
125+
return mkApp9
126+
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.ite_congr)
127+
discrExpr lhsExpr rhsExpr
128+
discrEvalExpr lhsEvalExpr rhsEvalExpr
129+
discrProof lhsProof rhsProof
130+
return ⟨boolExpr, proof, expr⟩
131+
102132
end ReifiedBVLogical
103133

104134
end Frontend

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide/ReifiedLemmas.lean

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,52 +18,55 @@ open Lean.Meta
1818

1919
/--
2020
This function adds the two lemmas:
21-
- `boolExpr = true → atomExpr = 1#1`
22-
- `boolExpr = false → atomExpr = 0#1`
23-
It assumes that `boolExpr` and `atomExpr` are the expressions corresponding to `bool` and `atom`.
24-
Furthermore it assumes that `atomExpr` is of the form `BitVec.ofBool boolExpr`.
21+
- `discrExpr = true → atomExpr = lhsExpr`
22+
- `discrExpr = false → atomExpr = rhsExpr`
23+
It assumes that `discrExpr`, `lhsExpr` and `rhsExpr` are the expressions corresponding to `discr`,
24+
`lhs` and `rhs`. Furthermore it assumes that `atomExpr` is of the form
25+
`if discrExpr = true then lhsExpr else rhsExpr`.
2526
-/
26-
def addOfBoolLemmas (bool : ReifiedBVLogical) (atom : ReifiedBVExpr) (boolExpr atomExpr : Expr) :
27-
LemmaM Unit := do
28-
let some ofBoolTrueLemmamkOfBoolTrueLemma bool atom boolExpr atomExpr | return ()
29-
LemmaM.addLemma ofBoolTrueLemma
30-
let some ofBoolFalseLemmamkOfBoolFalseLemma bool atom boolExpr atomExpr | return ()
31-
LemmaM.addLemma ofBoolFalseLemma
27+
def addIfLemmas (discr : ReifiedBVLogical) (atom lhs rhs : ReifiedBVExpr)
28+
(discrExpr atomExpr lhsExpr rhsExpr : Expr) : LemmaM Unit := do
29+
let some trueLemmamkIfTrueLemma discr atom lhs rhs discrExpr atomExpr lhsExpr rhsExpr | return ()
30+
LemmaM.addLemma trueLemma
31+
let some falseLemmamkIfFalseLemma discr atom lhs rhs discrExpr atomExpr lhsExpr rhsExpr | return ()
32+
LemmaM.addLemma falseLemma
3233
where
33-
mkOfBoolTrueLemma (bool : ReifiedBVLogical) (atom : ReifiedBVExpr) (boolExpr atomExpr : Expr) :
34-
M (Option SatAtBVLogical) := mkOfBoolLemma bool atom boolExpr atomExpr true 1#1
34+
mkIfTrueLemma (discr : ReifiedBVLogical) (atom lhs rhs : ReifiedBVExpr)
35+
(discrExpr atomExpr lhsExpr rhsExpr : Expr) : M (Option SatAtBVLogical) :=
36+
mkIfLemma true discr atom lhs rhs discrExpr atomExpr lhsExpr rhsExpr
3537

36-
mkOfBoolFalseLemma (bool : ReifiedBVLogical) (atom : ReifiedBVExpr) (boolExpr atomExpr : Expr) :
37-
M (Option SatAtBVLogical) := mkOfBoolLemma bool atom boolExpr atomExpr false 0#1
38+
mkIfFalseLemma (discr : ReifiedBVLogical) (atom lhs rhs : ReifiedBVExpr)
39+
(discrExpr atomExpr lhsExpr rhsExpr : Expr) : M (Option SatAtBVLogical) :=
40+
mkIfLemma false discr atom lhs rhs discrExpr atomExpr lhsExpr rhsExpr
3841

39-
mkOfBoolLemma (bool : ReifiedBVLogical) (atom : ReifiedBVExpr) (boolExpr atomExpr : Expr)
40-
(boolVal : Bool) (resVal : BitVec 1) : M (Option SatAtBVLogical) := do
42+
mkIfLemma (discrVal : Bool) (discr : ReifiedBVLogical) (atom lhs rhs : ReifiedBVExpr)
43+
(discrExpr atomExpr lhsExpr rhsExpr : Expr) : M (Option SatAtBVLogical) := do
44+
let resExpr := if discrVal then lhsExpr else rhsExpr
45+
let resValExpr := if discrVal then lhs else rhs
4146
let lemmaName :=
42-
match boolVal with
43-
| .true => ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_true
44-
| .false => ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_false
47+
if discrVal then
48+
``Std.Tactic.BVDecide.Reflect.BitVec.if_true
49+
else
50+
``Std.Tactic.BVDecide.Reflect.BitVec.if_false
51+
let discrValExpr := toExpr discrVal
52+
let discrVal ← ReifiedBVLogical.mkBoolConst discrVal
4553

46-
let boolValExpr := toExpr boolVal
47-
let boolVal ← ReifiedBVLogical.mkBoolConst boolVal
48-
let resExpr := toExpr resVal
49-
let resValExpr ← ReifiedBVExpr.mkBVConst resVal
54+
let eqDiscrExpr ← mkAppM ``BEq.beq #[discrExpr, discrValExpr]
55+
let eqDiscr ← ReifiedBVLogical.mkGate discr discrVal discrExpr discrValExpr .beq
5056

51-
let eqBoolExpr ← mkAppM ``BEq.beq #[boolExpr, boolValExpr]
52-
let eqBool ← ReifiedBVLogical.mkGate bool boolVal boolExpr boolValExpr .beq
53-
54-
let eqBVExpr ← mkAppM ``BEq.beq #[mkApp (mkConst ``BitVec.ofBool) boolExpr, resExpr]
57+
let eqBVExpr ← mkAppM ``BEq.beq #[atomExpr, resExpr]
5558
let some eqBVPred ← ReifiedBVPred.mkBinPred atom resValExpr atomExpr resExpr .eq | return none
5659
let eqBV ← ReifiedBVLogical.ofPred eqBVPred
5760

5861
let trueExpr := mkConst ``Bool.true
59-
let impExpr ← mkArrow (← mkEq eqBoolExpr trueExpr) (← mkEq eqBVExpr trueExpr)
62+
let impExpr ← mkArrow (← mkEq eqDiscrExpr trueExpr) (← mkEq eqBVExpr trueExpr)
6063
let decideImpExpr ← mkAppOptM ``Decidable.decide #[some impExpr, none]
61-
let imp ← ReifiedBVLogical.mkGate eqBool eqBV eqBoolExpr eqBVExpr .imp
64+
let imp ← ReifiedBVLogical.mkGate eqDiscr eqBV eqDiscrExpr eqBVExpr .imp
6265

6366
let proof := do
6467
let evalExpr ← ReifiedBVLogical.mkEvalExpr imp.expr
6568
let congrProof ← imp.evalsAtAtoms
66-
let lemmaProof := mkApp (mkConst lemmaName) boolExpr
69+
let lemmaProof := mkApp4 (mkConst lemmaName) (toExpr lhs.width) discrExpr lhsExpr rhsExpr
6770
return mkApp4
6871
(mkConst ``Std.Tactic.BVDecide.Reflect.Bool.lemma_congr)
6972
decideImpExpr

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide/Reify.lean

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ where
4747
binaryReflection lhsExpr rhsExpr .udiv ``Std.Tactic.BVDecide.Reflect.BitVec.udiv_congr
4848
| HMod.hMod _ _ _ _ lhsExpr rhsExpr =>
4949
binaryReflection lhsExpr rhsExpr .umod ``Std.Tactic.BVDecide.Reflect.BitVec.umod_congr
50-
| BitVec.sdiv _ lhsExpr rhsExpr =>
51-
binaryReflection lhsExpr rhsExpr .sdiv ``Std.Tactic.BVDecide.Reflect.BitVec.sdiv_congr
5250
| Complement.complement _ _ innerExpr =>
5351
unaryReflection innerExpr .not ``Std.Tactic.BVDecide.Reflect.BitVec.not_congr
5452
| HShiftLeft.hShiftLeft _ β _ _ innerExpr distanceExpr =>
@@ -207,11 +205,15 @@ where
207205
.rotateRight
208206
``BVUnOp.rotateRight
209207
``Std.Tactic.BVDecide.Reflect.BitVec.rotateRight_congr
210-
| BitVec.ofBool boolExpr =>
211-
let some bool ← ReifiedBVLogical.of boolExpr | return none
212-
let atomExpr := (mkApp (mkConst ``BitVec.ofBool) boolExpr)
213-
let some atom ← ReifiedBVExpr.bitVecAtom atomExpr | return none
214-
addOfBoolLemmas bool atom boolExpr atomExpr
208+
| ite _ discrExpr _ lhsExpr rhsExpr =>
209+
let_expr Eq α discrExpr val := discrExpr | return none
210+
let_expr Bool := α | return none
211+
let_expr Bool.true := val | return none
212+
let some atom ← ReifiedBVExpr.bitVecAtom x | return none
213+
let some discr ← ReifiedBVLogical.of discrExpr | return none
214+
let some lhs ← goOrAtom lhsExpr | return none
215+
let some rhs ← goOrAtom rhsExpr | return none
216+
addIfLemmas discr atom lhs rhs discrExpr x lhsExpr rhsExpr
215217
return some atom
216218
| _ => return none
217219

@@ -371,6 +373,14 @@ where
371373
| Bool => gateReflection lhsExpr rhsExpr .beq
372374
| BitVec _ => goPred t
373375
| _ => return none
376+
| ite _ discrExpr _ lhsExpr rhsExpr =>
377+
let_expr Eq α discrExpr val := discrExpr | return none
378+
let_expr Bool := α | return none
379+
let_expr Bool.true := val | return none
380+
let some discr ← goOrAtom discrExpr | return none
381+
let some lhs ← goOrAtom lhsExpr | return none
382+
let some rhs ← goOrAtom rhsExpr | return none
383+
return some (← ReifiedBVLogical.mkIte discr lhs rhs discrExpr lhsExpr rhsExpr)
374384
| _ => goPred t
375385

376386
/--

src/Lean/Elab/Tactic/BVDecide/Frontend/Normalize.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ builtin_simproc [bv_normalize] bv_add_const' (((_ : BitVec _) + (_ : BitVec _))
128128
else
129129
return .continue
130130

131+
attribute [builtin_bv_normalize_proc↓] reduceIte
132+
131133
/--
132134
A pass in the normalization pipeline. Takes the current goal and produces a refined one or closes
133135
the goal fully, indicated by returning `none`.

src/Std/Tactic/BVDecide/Bitblast/BVExpr/Basic.lean

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,6 @@ inductive BVBinOp where
7373
Unsigned modulo.
7474
-/
7575
| umod
76-
/--
77-
Signed division.
78-
-/
79-
| sdiv
8076

8177
namespace BVBinOp
8278

@@ -88,7 +84,6 @@ def toString : BVBinOp → String
8884
| mul => "*"
8985
| udiv => "/ᵤ"
9086
| umod => "%ᵤ"
91-
| sdiv => "/ₛ"
9287

9388
instance : ToString BVBinOp := ⟨toString⟩
9489

@@ -103,7 +98,6 @@ def eval : BVBinOp → (BitVec w → BitVec w → BitVec w)
10398
| mul => (· * ·)
10499
| udiv => (· / ·)
105100
| umod => (· % · )
106-
| sdiv => BitVec.sdiv
107101

108102
@[simp] theorem eval_and : eval .and = ((· &&& ·) : BitVec w → BitVec w → BitVec w) := by rfl
109103
@[simp] theorem eval_or : eval .or = ((· ||| ·) : BitVec w → BitVec w → BitVec w) := by rfl
@@ -112,7 +106,6 @@ def eval : BVBinOp → (BitVec w → BitVec w → BitVec w)
112106
@[simp] theorem eval_mul : eval .mul = ((· * ·) : BitVec w → BitVec w → BitVec w) := by rfl
113107
@[simp] theorem eval_udiv : eval .udiv = ((· / ·) : BitVec w → BitVec w → BitVec w) := by rfl
114108
@[simp] theorem eval_umod : eval .umod = ((· % ·) : BitVec w → BitVec w → BitVec w) := by rfl
115-
@[simp] theorem eval_sdiv : eval .sdiv = (BitVec.sdiv : BitVec w → BitVec w → BitVec w) := by rfl
116109

117110
end BVBinOp
118111

@@ -448,6 +441,8 @@ def eval (assign : BVExpr.Assignment) (expr : BVLogicalExpr) : Bool :=
448441
@[simp] theorem eval_const : eval assign (.const b) = b := rfl
449442
@[simp] theorem eval_not : eval assign (.not x) = !eval assign x := rfl
450443
@[simp] theorem eval_gate : eval assign (.gate g x y) = g.eval (eval assign x) (eval assign y) := rfl
444+
@[simp] theorem eval_ite :
445+
eval assign (.ite d l r) = if (eval assign d) then (eval assign l) else (eval assign r) := rfl
451446

452447
def Sat (x : BVLogicalExpr) (assign : BVExpr.Assignment) : Prop := eval assign x = true
453448

src/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Impl/Expr.lean

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.SignExtend
2121
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.Mul
2222
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.Udiv
2323
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.Umod
24-
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.Sdiv
2524

2625
/-!
2726
This module contains the implementation of a bitblaster for `BitVec` expressions (`BVExpr`).
@@ -118,13 +117,6 @@ where
118117
dsimp only at hlaig hraig
119118
omega
120119
⟨res, this⟩
121-
| .sdiv =>
122-
let res := bitblast.blastSdiv aig ⟨lhs, rhs⟩
123-
have := by
124-
apply AIG.LawfulVecOperator.le_size_of_le_aig_size (f := bitblast.blastSdiv)
125-
dsimp only at hlaig hraig
126-
omega
127-
⟨res, this⟩
128120
| .un op expr =>
129121
let ⟨⟨eaig, evec⟩, heaig⟩ := go aig expr
130122
match op with
@@ -235,7 +227,7 @@ theorem bitblast.go_decl_eq (aig : AIG BVBit) (expr : BVExpr w) :
235227
rw [AIG.LawfulVecOperator.decl_eq (f := blastConst)]
236228
| bin lhs op rhs lih rih =>
237229
match op with
238-
| .and | .or | .xor | .add | .mul | .udiv | .umod | .sdiv =>
230+
| .and | .or | .xor | .add | .mul | .udiv | .umod =>
239231
dsimp only [go]
240232
have := (bitblast.go aig lhs).property
241233
have := (go (go aig lhs).1.aig rhs).property

0 commit comments

Comments
 (0)