Bit-Blasting ACL2 Theorems
Interactive theorem proving requires a lot of human guidance. Proving a property involves (1) figuring out why it holds, then (2) coaxing the theorem prover into believing it. Both steps can take a long time. We explain how to use GL, a framework for proving finite ACL2 theorems with BDD- or SAT-based reasoning. This approach makes it unnecessary to deeply understand why a property is true, and automates the process of admitting it as a theorem. We use GL at Centaur Technology to verify execution units for x86 integer, MMX, SSE, and floating-point arithmetic.
💡 Research Summary
The paper presents GL, a framework integrated into ACL2 that enables fully automatic proof of finite theorems by “bit‑blasting” them into Boolean formulas and solving those formulas with either Binary Decision Diagrams (BDDs) or SAT‑based And‑Inverter Graphs (AIGs). The authors argue that traditional interactive theorem proving often requires deep insight into why a property holds and substantial manual guidance, whereas many hardware verification problems are essentially finite and can be decided automatically. GL bridges this gap by providing a symbolic execution engine that works directly on ACL2 objects encoded as symbolic objects.
A symbolic object is a tagged representation of an ACL2 value where numbers become (:g-number <lsb‑bits>), Booleans become (:g-boolean . <expr>), conditionals become (:g-ite <test> <then> <else>), and so on. The bits of a number are Boolean variables or expressions; GL builds these expressions using either a hons‑based BDD package or a hons‑based AIG package. Symbolic execution proceeds by expanding ACL2 function definitions until primitive operations are reached, then applying specialized symbolic kernels for those primitives (e.g., ripple‑carry addition for :g-number). This yields new symbolic objects whose Boolean components capture all possible concrete values consistent with the original inputs.
To prove a theorem, the user writes a def-gl-thm form that separates hypothesis (:hyp) and conclusion (:concl) and supplies :g-bindings describing how each free variable should be represented symbolically. For example, a 32‑bit unsigned integer variable x can be bound with (g-int 0 1 33), which creates a 33‑bit signed symbolic number whose most‑significant bit is the sign. GL then automatically refines this representation using the hypothesis (e.g., fixing the sign bit to 0 for an unsigned range). The conclusion is symbolically executed on these objects; the resulting symbolic object is examined to see whether it can ever evaluate to nil. In BDD mode, the result is a canonical constant t, making the proof trivial. In AIG mode, the result is a large Boolean formula; GL hands it to an external SAT solver, which confirms that the formula is unsatisfiable (i.e., it can never be false). If the formula were satisfiable, GL would extract a concrete assignment to the Boolean variables and present it as a counterexample.
The authors illustrate the approach with two substantial case studies. The first is a fast bit‑count algorithm for 32‑bit integers (the classic “popcount” trick). Using def-gl-thm, they prove that the ACL2 implementation fast-logcount-32 is equivalent to the built‑in logcount for all unsigned 32‑bit inputs. The proof completes in 0.09 seconds, whereas exhaustive testing of the 2³² cases takes 143 seconds. Scaling to 64‑ and 128‑bit versions still finishes in under a second, demonstrating GL’s superior scalability. The second case study revisits a UTF‑8 well‑formedness proof originally done with exhaustive testing (67 seconds). GL proves the same property in 0.17 seconds without any auxiliary testing functions or lemmas, and automatically generates counterexamples when the property is violated (e.g., when a 32‑bit multiply was mistakenly used).
Performance considerations are discussed in depth. BDDs are canonical and make equality checks trivial, but they can consume large amounts of memory for complex formulas. AIGs are more compact and, when paired with a modern SAT solver, can outperform BDDs on problems with many variables and deep logical structure. The paper provides guidance on selecting the appropriate backend and on tuning symbolic execution (e.g., providing more efficient function definitions, using :g-bindings that reduce the symbolic space, or decomposing a hard goal into subgoals).
Debugging facilities are also covered. GL can print intermediate symbolic objects, visualize BDD/AIG graphs, and report which Boolean assignments lead to a failure, aiding users in diagnosing why a proof attempt failed. The authors note that GL’s symbolic objects are deliberately restricted in the :g-bindings syntax to make coverage proofs automatic; nevertheless, GL internally optimizes these objects using the hypothesis to achieve the minimal necessary representation.
In conclusion, GL offers a practical, high‑performance method for automatically proving finite ACL2 theorems, eliminating the need for deep human insight into the underlying algorithmic correctness. Its integration into ACL2 4.3, reliance only on the verified ACL2(h) extensions, and successful application to real hardware verification tasks at Centaur Technology (including x86 integer, MMX, SSE, and floating‑point units) demonstrate its robustness and industrial relevance.
Comments & Academic Discussion
Loading comments...
Leave a Comment