Skip to content

Commit a6efbe3

Browse files
committed
prop idea. casting. emt tactics. pcode proof state
1 parent 0266c5b commit a6efbe3

File tree

6 files changed

+155
-11
lines changed

6 files changed

+155
-11
lines changed

src/kdrag/cast.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import kdrag.smt as smt
2+
3+
cast_table = {}
4+
5+
6+
def cast(s: smt.SortRef, e: object) -> smt.ExprRef:
7+
if isinstance(e, smt.ExprRef):
8+
s1 = e.sort()
9+
if s1.eq(s):
10+
return e
11+
else:
12+
key = (s, e.sort())
13+
else:
14+
key = (s, type(e))
15+
coerce = cast_table.get(key)
16+
if coerce is not None:
17+
return coerce(e)
18+
else:
19+
# if isinstance(e, smt.SeqRef):
20+
# elif isinstance(e, smt.ArraySortRef):
21+
return s.cast(e)
22+
23+
24+
def cast_dt(dt: smt.DatatypeSortRef, e: smt.DatatypeRef) -> smt.DatatypeRef:
25+
"""
26+
Simple field name based downcasting between two struct-like datatypes
27+
28+
"""
29+
dt1 = e.sort()
30+
assert dt1.num_constructors() == 1 and dt.num_constructors() == 1
31+
constr, constr1 = dt.constructor(0), dt1.constructor(0)
32+
assert constr.arity() <= constr1.arity()
33+
args = []
34+
for i in range(constr.arity()):
35+
acc = dt.accessor(0, i)
36+
args.append(getattr(e, acc.name())) # TODO: consider extra cast here
37+
return constr(*args)
38+
39+
40+
"""
41+
def coerce_exprs(a, b):
42+
return smt._coerce_exprs(a, b)
43+
44+
45+
def coerce_expr_merge(s: smt.SortRef, a: smt.ExprRef):
46+
return smt._coerce_expr_merge(s, a)
47+
"""
48+
49+
50+
def subsort(s: smt.SortRef, t: smt.SortRef) -> bool:
51+
return s.subsort(t)

src/kdrag/contrib/pcode/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,13 @@ def __init__(self, filename=None, langid="x86:LE:64:default"):
460460
self.definitions.extend(
461461
[bv.store_concats(self.bits, size, le=le) for size in [16, 32, 64]]
462462
)
463+
# Helpers
464+
self.select16 = bv.select_concats(self.bits, 16, le=le)
465+
self.select32 = bv.select_concats(self.bits, 32, le=le)
466+
self.select64 = bv.select_concats(self.bits, 64, le=le)
467+
self.store16 = bv.store_concats(self.bits, 16, le=le)
468+
self.store32 = bv.store_concats(self.bits, 32, le=le)
469+
self.store64 = bv.store_concats(self.bits, 64, le=le)
463470
if filename is not None:
464471
self.load(filename)
465472

src/kdrag/contrib/pcode/asmspec.py

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,16 @@ def run_all_paths(
605605

606606

607607
class VCProofState(kd.tactics.ProofState):
608-
def __init__(self, vc: VerificationCondition, ctx: pcode.BinaryContext):
608+
def __init__(
609+
self, vc: VerificationCondition, ctx: pcode.BinaryContext, _parent=None
610+
):
609611
self.vc = vc
610612
self.binctx = ctx
611-
super().__init__(kd.tactics.Goal(sig=[], ctx=[], goal=vc.vc(ctx)))
613+
super().__init__(
614+
kd.tactics.Goal(sig=[], ctx=[], goal=vc.vc(ctx)), _parent=_parent
615+
)
616+
# self.intros()
617+
# self.split(at=0)
612618

613619
def auto(self, **kwargs):
614620
try:
@@ -623,21 +629,61 @@ def auto(self, **kwargs):
623629
self.vc.countermodel(self.binctx, countermodel),
624630
)
625631

632+
def __repr__(self):
633+
return super().__repr__() + f"\n\nfrom VC: {self.vc}"
634+
635+
636+
class AsmProofState:
637+
def __init__(self, ctx: pcode.BinaryContext, spec: AsmSpec):
638+
self.ctx = ctx
639+
self.spec = spec
640+
# self._spec = spec.copy() # TODO copy
641+
mem = self.ctx.init_mem()
642+
tracestates, vcs = init_trace_states(self.ctx, mem, self.spec)
643+
while tracestates:
644+
tracestate = tracestates.pop()
645+
new_tracestates, new_vcs = execute_spec_and_insn(
646+
tracestate, self.spec, self.ctx
647+
)
648+
vcs.extend(new_vcs)
649+
tracestates.extend(new_tracestates)
650+
self.vcs = tuple(vcs)
651+
self.pfs = []
652+
653+
def auto(self, n, **kwargs):
654+
vc = self.vcs[n]
655+
self.pfs.append(vc.verify(self.ctx, **kwargs))
656+
657+
def lemma(self, n) -> VCProofState:
658+
return VCProofState(self.vcs[n], self.ctx, _parent=self)
659+
660+
def exact(self, pf: kd.Proof):
661+
# it's goofy, but this is the current ProofState api
662+
self.pfs.append(pf)
663+
664+
def qed(self):
665+
assert len(self.vcs) == len(self.pfs)
666+
assert all(
667+
isinstance(pf, kd.Proof) and pf.thm.eq(vc.vc(self.ctx))
668+
for vc, pf in zip(self.vcs, self.pfs)
669+
)
670+
626671

627672
class Debug:
628673
def __init__(
629-
self, ctx: pcode.BinaryContext, spec: Optional[AsmSpec] = None, verbose=True
674+
self,
675+
ctx: pcode.BinaryContext,
676+
spec: AsmSpec = AsmSpec(),
677+
verbose=True,
630678
):
631679
self.ctx = ctx
632-
if spec is None:
633-
self.spec = AsmSpec()
634-
else:
635-
self.spec: AsmSpec = spec
680+
self.spec: AsmSpec = spec
636681
self.tracestates: list[TraceState] = []
637682
self.vcs: list[VerificationCondition] = []
638683
self.breakpoints = set()
639684
self.verbose = verbose
640685
self._cur_model = None
686+
self.pfs = []
641687

642688
def spec_file(self, filename: str):
643689
self.spec = AsmSpec.of_file(filename, self.ctx)
@@ -723,16 +769,15 @@ def pop_run(self):
723769

724770
def pop_verify(self, **kwargs):
725771
vc = self.vcs.pop()
726-
vc.verify(self.ctx, **kwargs)
772+
self.pfs.append((vc, vc.verify(self.ctx, **kwargs)))
727773

728774
def verify(self, **kwargs):
729775
if not self.vcs:
730776
raise Exception("No verification conditions to verify")
731777
if self.tracestates:
732778
raise Exception("There are still trace states to execute")
733779
while self.vcs:
734-
vc = self.vcs.pop(0)
735-
vc.verify(self.ctx, **kwargs)
780+
self.pop_verify(**kwargs)
736781

737782
def pop_lemma(self) -> kd.tactics.ProofState:
738783
vc = self.vcs.pop()

src/kdrag/smt.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,10 @@ def DeclareSort(name):
468468
return sort_registry[tid]
469469

470470

471+
# Implicit tags for properties
471472
ExprRef.assumes = None
473+
ExprRef.prop = None
474+
FuncDeclRef.prop = None
472475

473476

474477
type FuncRef = ArrayRef | QuantifierRef

src/kdrag/tactics.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from dataclasses import dataclass
1515
import kdrag.parsers.microlean as microlean
1616
import kdrag.reflect as reflect
17+
import kdrag.solvers.egraph as egraph
1718

1819

1920
def FreshVar(name: str, sort: smt.SortRef, assume=None) -> smt.ExprRef:
@@ -717,6 +718,35 @@ def simp(self, at=None, unfold=False, path=None) -> "ProofState":
717718
)
718719
return self
719720

721+
def emt(self):
722+
"""
723+
Use egraph based equality modulo theories to simplify the goal.
724+
>>> x, y, z, w = smt.Ints("x y z w")
725+
>>> l = Lemma(smt.Implies(x + y + 1 == z, x + y + 1 == w))
726+
>>> l.intros()
727+
[x + y + 1 == z] ?|= x + y + 1 == w
728+
>>> l.emt()
729+
[x + y + 1 == z] ?|= z == w
730+
731+
"""
732+
goalctx = self.top_goal()
733+
ctx, goal = goalctx.ctx, goalctx.goal
734+
E = egraph.EGraph()
735+
E.solver.add(ctx)
736+
E.add_term(goal)
737+
for c in ctx:
738+
E.add_term(c)
739+
E.rebuild()
740+
newgoal = E.extract(goal)
741+
if newgoal.eq(goal):
742+
raise ValueError("EMT failed. Goal is already in simplest form.", goal)
743+
else:
744+
self.add_lemma(
745+
kd.kernel.prove(smt.Implies(smt.And(ctx), smt.Eq(goal, newgoal)))
746+
)
747+
self.goals[-1] = goalctx._replace(goal=newgoal)
748+
return self
749+
720750
def cases(self, t):
721751
"""
722752
`cases` let's us consider an object by cases.

src/kdrag/tele.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
"""
2+
Refinement subtyping
3+
4+
- https://www.philipzucker.com/refinement_kdrag1/ Semantic Refinement/Dependent Typing for Knuckledragger/SMTLIB Pt 1
5+
- https://belle.sourceforge.net/doc/subtypes.pdf Predicate Subtyping with Predicate Sets - Joe Hurd
6+
7+
"""
8+
19
import kdrag.smt as smt
210
import kdrag as kd
311
import functools
412

5-
type SubSort = smt.QuantifierRef | smt.ArrayRef
13+
type SubSort = smt.FuncRef
614
type Type = SubSort
715
# User telescope
816
"""

0 commit comments

Comments
 (0)