Included Books
other
(in-package "ACL2")
include-book
(include-book "ihs-init")
include-book
(include-book "ihs-theories")
include-book
(include-book "std/util/defval" :dir :system)
local
(local (include-book "math-lemmas"))
local
(local (include-book "quotient-remainder-lemmas"))
other
(deflabel begin-logops-definitions)
include-book
(include-book "basic-definitions")
local
(local (defthm x*y->-1 (implies (and (force (real/rationalp x)) (force (real/rationalp y)) (or (and (> x 1) (>= y 1)) (and (>= x 1) (> y 1)))) (> (* x y) 1)) :rule-classes :linear :hints (("Goal" :in-theory (enable x*y>1-positive) :cases ((equal y 1) (equal x 1))))))
local
(local (defthm x*y->=-1 (implies (and (force (real/rationalp x)) (force (real/rationalp y)) (>= x 1) (>= y 1)) (>= (* x y) 1)) :rule-classes :linear :hints (("Goal" :in-theory (disable <-*-left-cancel commutativity-of-*) :use ((:instance <-*-left-cancel (z y) (x 1) (y x)))))))
local
(local (defthm x-<-y*z (implies (and (force (real/rationalp x)) (force (real/rationalp y)) (force (real/rationalp z)) (or (and (<= 0 y) (< x y) (<= 1 z)) (and (< 0 y) (<= x y) (< 1 z)))) (and (< x (* y z)) (< x (* z y)))) :hints (("Goal" :in-theory (disable <-*-left-cancel <-y-*-y-x) :use ((:instance <-*-left-cancel (z y) (x 1) (y z)))))))
local
(local (defthm x-<=-y*z (implies (and (force (real/rationalp x)) (force (real/rationalp y)) (force (real/rationalp z)) (<= x y) (<= 0 y) (<= 1 z)) (and (<= x (* y z)) (<= x (* z y)))) :hints (("Goal" :in-theory (disable <-*-left-cancel <-y-*-y-x) :use ((:instance <-*-left-cancel (z y) (x 1) (y z)))))))
other
(defsection bitp-basics :parents (bitp) (defthm bitp-mod-2 (implies (integerp i) (bitp (mod i 2))) :rule-classes ((:rewrite) (:generalize :corollary (implies (integerp i) (or (equal (mod i 2) 0) (equal (mod i 2) 1))))) :hints (("Goal" :in-theory (enable linearize-mod)))))
local
(local (in-theory (enable unsigned-byte-p signed-byte-p integer-range-p)))
other
(defsection unsigned-byte-p-basics :parents (unsigned-byte-p) (defthm unsigned-byte-p-forward (implies (unsigned-byte-p bits i) (and (integerp i) (>= i 0) (< i (expt 2 bits)))) :rule-classes :forward-chaining) (defthmd unsigned-byte-p-unsigned-byte-p (implies (and (unsigned-byte-p size i) (integerp size1) (>= size1 size)) (unsigned-byte-p size1 i)) :hints (("Goal" :in-theory (disable expt-is-weakly-increasing-for-base>1) :use ((:instance expt-is-weakly-increasing-for-base>1 (r 2) (i size) (j size1)))))))
local
(local (in-theory (disable unsigned-byte-p)))
other
(defxdoc unsigned-byte-p-discussion :parents (unsigned-byte-p) :short "Discussion on how to use unsigned-byte-p" :long "<p>@(csee unsigned-byte-p) (and @(see signed-byte-p) for that matter) are tricky enough that there is no one-size-fits-all solution that everyone should use to reason about them. Depending on your problem you might try any of these strategies:</p> <ol> <li><i>Arithmetic</i> -- Leave unsigned-byte-p's regular definition enabled and try to reason about the resulting inequalities. This sometimes works and may be a good approach if you have goals involving "non bit-vector functions" like +, *, /, etc. I usually don't use this approach but I haven't done a lot of proofs about true arithmetic functions.</li> <li><i>Induction</i> -- Disable unsigned-byte-p's regular definition but instead enable an alternate definition, e.g., the centaur/bitops/ihsext-basics book has unsigned-byte-p**, which is a recursive version that works well for induction. This definition is in the ihsext-recursive-redefs ruleset and also works well with other ** definitions like logand**. This is often a good strategy when proving lemmas about unsigned-byte-p but is probably mainly useful when reasoning about new recursive functions.</li> <li><i>Vector</i> -- Leave @(see unsigned-byte-p) disabled except to prove lemmas, and expect to reason about (unsigned-byte-p n x) via lemmas. I think I usually prefer this strategy as it feels more reliable/less magical than reasoning about arithmetic inequalities. Some useful books: <ol> <li>bitops/ihsext-basics proves the nice/obvious lemmas about signed/unsigned-byte-p on many bit-vector functions like logior, logand, etc.</li> <li>bitops/signed-byte-p has lemmas about signed/unsigned-byte-p for some arithmetic functions (+, -, *) and also extended lemmas about bit-vector stuff. It's often very handy for the kinds of guard obligations that arise from things like (the (unsigned-byte 32) x).</li> </ol></li> </ol> <p>We have occasionally written wrapper functions like @('u32p'), but, I think that perhaps the only reason we did this was for macros like @(see def-typed-record), where we needed a unary predicate to introduce a fancier data structure. Once we had the typed records in place, we just enabled these wrappers and did all our reasoning about @(see unsigned-byte-p). (I don't think you'd want to reason about a each various u32p, u64p, etc., individually.)</p> <p>In the context of FTY, I don't think you need wrappers, but if for some reason you do want to use them then that is probably basically fine. Note here that you have some choice for your fixing function. You can fix to 0 as you've done in your examples, but you might instead prefer to fix to @('(loghead n x)'). Why? When you use loghead, it preserves the lower @('N') bits, and this may interact much more nicely with rules about true bit-vector functions. This approach is also good for GL, where loghead is supported in an especially good way.</p> <p>That said, it should be possible to get by without wrappers; see for instance the definition of sizednum in centaur/fty/deftypes-tests.lisp, or the definition of vl-constint in centaur/vl/expr.lisp, both of which use a loghead-based approach to do the fixing. (The vl-constint example has a :require that is an inequality instead of an unsigned-byte-p term, but I don't think there's any particular reason to do it this way instead of the other.)</p> <p>In general there is good reason to expect it to sometimes be hard to work with unsigned-byte-p. For instance, consider a theorem like the following, from @('centaur/bitops/signed-byte-p.lisp'):</p> @({ (defthm lousy-unsigned-byte-p-of-*-mixed ;; Probably won't ever unify with anything. (implies (and (unsigned-byte-p n1 a) (unsigned-byte-p n2 b)) (unsigned-byte-p (+ n1 n2) (* a b))) :hints(("Goal" :use ((:instance upper-bound))))) }) <p>This would be a good rule to try on goals like @('(unsigned-byte-p 10 (* a b))'), but without some insight into @('a') and @('b') it's hard to know how to successfully instantiate @('N1/N2'). So you end up resorting to @(':use') hints, or special-case variants of this theorem (e.g., another theorem that says 7 bits * 3 bits --> 10 bits), or you do something more sophisticated with bind-free or similar.</p> <p>If you find yourself going down this road, you might see in particular Dave Greve's "Parameterized Congruences" paper from the 2006 workshop, which is implemented in the coi/nary/nary.lisp book. You could also look at Sol Swords' book to do something similar, see @(see contextual-rewriting).</p>")
other
(defsection signed-byte-p-basics :parents (signed-byte-p) (defthm signed-byte-p-forward (implies (signed-byte-p bits i) (and (integerp i) (>= i (- (expt 2 (- bits 1)))) (< i (expt 2 (- bits 1))))) :rule-classes :forward-chaining))
local
(local (in-theory (disable signed-byte-p)))
other
(defsection logbit-guard :parents (logops-definitions) :short "@(call logbit-guard) is a macro form of the guards for @(see logbit)." (defmacro logbit-guard (pos i) `(and (force (integerp ,POS)) (force (>= ,POS 0)) (force (integerp ,I)))))
other
(defsection logmask-guard :parents (logops-definitions) :short "@(call logmask-guard) is a macro form of the guards for @(see logmask)." (defmacro logmask-guard (size) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)))))
other
(defsection loghead-guard :parents (logops-definitions) :short "@(call loghead-guard) is a macro form of the guards for @(see loghead)." (defmacro loghead-guard (size i) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)))))
other
(defsection logtail-guard :parents (logops-definitions) :short "@(call logtail-guard) is a macro form of the guards for @(see logtail)." (defmacro logtail-guard (pos i) `(and (force (integerp ,POS)) (force (>= ,POS 0)) (force (integerp ,I)))))
other
(defsection logapp-guard :parents (logops-definitions) :short "@(call logapp-guard) is a macro form of the guards for @(see logapp)." (defmacro logapp-guard (size i j) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)) (force (integerp ,J)))))
other
(defsection logrpl-guard :parents (logops-definitions) :short "@(call logrpl-guard) is a macro form of the guards for @(see logrpl)." (defmacro logrpl-guard (size i j) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)) (force (integerp ,J)))))
other
(defsection logext-guard :parents (logops-definitions) :short "@(call logext-guard) is a macro form of the guards for @(see logext)." (defmacro logext-guard (size i) `(and (force (integerp ,SIZE)) (force (> ,SIZE 0)) (force (integerp ,I)))))
other
(defsection logrev-guard :parents (logops-definitions) :short "@(call logrev-guard) is a macro form of the guards for @(see logrev)." (defmacro logrev-guard (size i) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)))))
other
(defsection logextu-guard :parents (logops-definitions) :short "@(call logextu-guard) is a macro form of the guards for @(see logextu)." (defmacro logextu-guard (final-size ext-size i) `(and (force (integerp ,FINAL-SIZE)) (force (>= ,FINAL-SIZE 0)) (force (integerp ,EXT-SIZE)) (force (> ,EXT-SIZE 0)) (force (integerp ,I)))))
other
(defsection lognotu-guard :parents (logops-definitions) :short "@(call lognotu-guard) is a macro form of the guards for @(see lognotu)." (defmacro lognotu-guard (size i) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)))))
other
(defsection ashu-guard :parents (logops-definitions) :short "@(call ashu-guard) is a macro form of the guards for @(see ashu)." (defmacro ashu-guard (size i cnt) `(and (force (integerp ,SIZE)) (force (> ,SIZE 0)) (force (integerp ,I)) (force (integerp ,CNT)))))
other
(defsection lshu-guard :parents (logops-definitions) :short "@(call lshu-guard) is a macro form of the guards for @(see lshu)." (defmacro lshu-guard (size i cnt) `(and (force (integerp ,SIZE)) (force (>= ,SIZE 0)) (force (integerp ,I)) (force (integerp ,CNT)))))
other
(defsection logcdr-basics :parents (logcdr) (defthm logcdr-<-0 (equal (< (logcdr i) 0) (and (integerp i) (< i 0)))) (defthm justify-logcdr-induction (and (implies (> i 0) (< (logcdr i) i)) (implies (< i -1) (< i (logcdr i)))) :hints (("Goal" :in-theory (enable logcdr)))))
other
(defsection logcons-basics :parents (logcons) (defthm logcons-<-0 (equal (< (logcons b i) 0) (and (integerp i) (< i 0))) :hints (("Goal" :in-theory (enable bfix)))))
other
(defsection loghead-basics :parents (loghead) (defthm unsigned-byte-p-loghead (implies (and (>= size1 size) (integerp size) (>= size 0) (integerp size1)) (unsigned-byte-p size1 (loghead size i))) :hints (("Goal" :in-theory (e/d (unsigned-byte-p) (expt-is-weakly-increasing-for-base>1)) :use ((:instance expt-is-weakly-increasing-for-base>1 (r 2) (i size) (j size1)))))) (defthm loghead-upper-bound (< (loghead size i) (expt 2 size)) :rule-classes (:linear :rewrite)))
other
(defsection logapp-basics :parents (logapp) (defthm logapp-<-0 (implies (logapp-guard size i j) (equal (< (logapp size i j) 0) (< j 0))) :hints (("Goal" :in-theory (e/d (loghead) (x-<-y*z)) :use ((:instance x-<-y*z (x (mod i (expt 2 size))) (y (expt 2 size)) (z (abs j))))))))
expt-with-violated-guardstheorem
(defthm expt-with-violated-guards (and (implies (not (integerp i)) (equal (expt r i) 1)) (implies (not (acl2-numberp r)) (equal (expt r i) (expt 0 i)))) :hints (("Goal" :in-theory (enable expt))))
reduce-integerp-+-constanttheorem
(defthm reduce-integerp-+-constant (implies (and (syntaxp (constant-syntaxp i)) (integerp i)) (iff (integerp (+ i j)) (integerp (fix j)))))
how-could-this-have-been-left-out??theorem
(defthm how-could-this-have-been-left-out?? (equal (* 0 x) 0))
this-needs-to-be-added-to-quotient-remainder-lemmastheorem
(defthm this-needs-to-be-added-to-quotient-remainder-lemmas (implies (zerop y) (equal (mod x y) (fix x))) :hints (("Goal" :in-theory (enable mod))))
other
(defsection logext-basics :parents (logext) (defthm logext-bounds (implies (< 0 size) (and (>= (logext size i) (- (expt 2 (1- size)))) (< (logext size i) (expt 2 (1- size))))) :rule-classes ((:linear :trigger-terms ((logext size i))) (:rewrite)) :hints (("Goal" :in-theory (e/d (logapp loghead) (expt-is-increasing-for-base>1 exponents-add)) :use ((:instance expt-is-increasing-for-base>1 (r 2) (i (1- size)) (j size)))))) (defthm signed-byte-p-logext (implies (and (>= size1 size) (> size 0) (integerp size1) (integerp size)) (signed-byte-p size1 (logext size i))) :hints (("Goal" :in-theory (e/d (signed-byte-p logapp loghead) (expt-is-weakly-increasing-for-base>1 exponents-add)) :do-not '(eliminate-destructors) :use ((:instance expt-is-weakly-increasing-for-base>1 (r 2) (i (1- size)) (j (1- size1))))))))
other
(defsection logrev-basics :parents (logrev) (local (defun crock-induction (size size1 i j) (cond ((zp size) (+ size1 i j)) (t (crock-induction (1- size) (1+ size1) (logcdr i) (logcons (logcar i) j)))))) (local (defthm unsigned-byte-p-logrev1 (implies (and (unsigned-byte-p size1 j) (integerp size) (>= size 0)) (unsigned-byte-p (+ size size1) (logrev1 size i j))) :rule-classes nil :hints (("Goal" :in-theory (e/d (expt logcar logcons unsigned-byte-p) (exponents-add)) :induct (crock-induction size size1 i j))))) (defthm unsigned-byte-p-logrev (implies (and (>= size1 size) (>= size 0) (integerp size) (integerp size1)) (unsigned-byte-p size1 (logrev size i))) :hints (("Goal" :use ((:instance unsigned-byte-p-logrev1 (size size) (size1 0) (i i) (j 0)) (:instance unsigned-byte-p-unsigned-byte-p (size size) (size1 size1) (i (logrev size i))))))))
other
(defsection logsat-basics :parents (logsat) (local (in-theory (enable exponents-add-unrestricted))) (defthm logsat-bounds (implies (< 0 size) (and (>= (logsat size i) (- (expt 2 size))) (< (logsat size i) (expt 2 size)))) :rule-classes ((:linear :trigger-terms ((logsat size i))) (:rewrite))) (local (in-theory (disable exponents-add-unrestricted))) (defthm signed-byte-p-logsat (implies (and (>= size1 size) (> size 0) (integerp size1) (integerp size)) (signed-byte-p size1 (logsat size i))) :hints (("Goal" :in-theory (e/d (signed-byte-p) (expt-is-weakly-increasing-for-base>1 exponents-add)) :do-not '(eliminate-destructors) :use ((:instance expt-is-weakly-increasing-for-base>1 (r 2) (i (1- size)) (j (1- size1))))))))
other
(defsection logextu-basics :parents (logextu) (defthm unsigned-byte-p-logextu (implies (and (>= size1 final-size) (>= final-size 0) (integerp final-size) (integerp size1)) (unsigned-byte-p size1 (logextu final-size ext-size i)))))
other
(defsection lognotu-basics :parents (lognotu) (defthm unsigned-byte-p-lognotu (implies (and (>= size1 size) (>= size 0) (integerp size) (integerp size1)) (unsigned-byte-p size1 (lognotu size i)))))
other
(defsection ashu-basics :parents (ashu) (defthm unsigned-byte-p-ashu (implies (and (>= size1 size) (>= size 0) (integerp size) (integerp size1)) (unsigned-byte-p size1 (ashu size i cnt)))))
other
(defsection lshu-basics :parents (lshu) (defthm unsigned-byte-p-lshu (implies (and (>= size1 size) (>= size 0) (integerp size) (integerp size1)) (unsigned-byte-p size1 (lshu size i cnt)))))
other
(defxdoc logops-byte-functions :parents (logops-definitions) :short "A portable implementation and extension of Common Lisp byte functions." :long "<p>The proposed Common Lisp standard [<a href='http://en.wikipedia.org/wiki/X3J13'>X3J13</a> Draft 14.10] defines a number of functions that operate on subfields of integers. These subfields are specified by @('(BYTE size position)'), which "indicates a byte of width size and whose bits have weights @($2^{position+size-1}$) through @($2^{pos}$), and whose representation is implementation dependent". Unfortunately, the standard does not specify what BYTE returns, only that whatever is returned is understood by the byte manipulation functions LDB, DPB, etc.</p> <p>This lack of complete specification makes it impossible for ACL2 to specify the byte manipulation functions of Common Lisp in a portable way. For example AKCL uses @('(cons size position)') as a byte specifier, whereas another implementation might use a special data structure to represent @('(byte size position)'). Since any theorem about the ACL2 built-ins is meant to be a theorem for all Common Lisp implementations, ACL2 cannot define BYTE.</p> <p>Therefore, we have provided a portable implementation of the byte operations specified by the draft standard. This behavior of this implementation should be consistent with every Common Lisp that provides the standard byte operations. Our byte specifier @('(bsp size pos)') is analogous to CLTL's @('(byte size pos)'), where size and pos are nonnegative integers. Note that the standard indicates that reading a byte of size 0 returns 0, and writing a byte of size 0 leaves the destination unchanged.</p> <p>This table indicates the correspondance between the Common Lisp byte operations and our portable implementation:</p> @({ Common Lisp This Implementation ------ ---- ---- -------------- (BYTE size position) (BSP size position) (BYTE-SIZE bytespec) (BSP-SIZE bsp) (BYTE-POSITION bytespec) (BSP-POSITION bsp) (LDB bytespec integer) (RDB bsp integer) (DPB newbyte bytespec integer) (WRB newbyte bsp integer) (LDB-TEST bytespec integer) (RDB-TEST bsp integer) (MASK-FIELD bytespec integer) (RDB-FIELD bsp integer) (DEPOSIT-FIELD newbyte bytespec integer) (WRB-FIELD newbyte bsp integer) }) <p>For more information, see the documentation for the functions listed above. If you are concerned about the efficiency of this implementation, see the file @('ihs/logops-efficiency-hack.lsp') for some notes.</p>")
other
(defsection bsp :parents (logops-byte-functions) :short "@(call bsp) returns a byte-specifier." :long "<p>This specifier designates a byte whose width is size and whose bits have weights 2^(pos) through 2^(pos+size-1). Both size and pos must be nonnegative integers.</p> <p>BSP is mnemonic for Byte SPecifier or Byte Size and Position, and is analogous to Common Lisp's @('(byte size position)').</p> <p>BSP is implemented as a macro for simplicity and convenience. One should always use BSP in preference to CONS, however, to ensure compatibility with future releases.</p> @(def bsp)" (defmacro bsp (size pos) `(cons ,SIZE ,POS)))
other
(define bspp (bsp) :parents (logops-byte-functions) :short "@(call bspp) recognizes objects produced by @(see bsp)." :returns bool :enabled t (and (consp bsp) (integerp (car bsp)) (>= (car bsp) 0) (integerp (cdr bsp)) (>= (cdr bsp) 0)) /// (defthm bspp-bsp (implies (and (integerp size) (>= size 0) (integerp pos) (>= pos 0)) (bspp (bsp size pos))) :hints (("Goal" :in-theory (enable bspp)))))
other
(define bsp-size ((bsp bspp)) :returns (size (and (integerp size) (>= size 0)) :rule-classes :type-prescription :hyp (bspp bsp) :name bsp-size-type) :parents (logops-byte-functions) :short "@('(bsp-size (bsp size pos)) = size')" :long "<p>This is analogous to Common Lisp's @('(byte-size bytespec)').</p>" :enabled t (car bsp))
other
(define bsp-position ((bsp bspp)) :returns (pos (and (integerp pos) (>= pos 0)) :rule-classes :type-prescription :hyp (bspp bsp) :name bsp-position-type) :parents (logops-byte-functions) :short "@('(bsp-position (bsp size pos)) = pos')" :long "<p>This is analogous to Common Lisp's @('(byte-position bytespec)').</p>" :enabled t (cdr bsp))
other
(define rdb ((bsp bspp) (i integerp)) :returns (nat (and (integerp nat) (>= nat 0)) :rule-classes :type-prescription :name rdb-type) :parents (logops-byte-functions) :short "@(call rdb) returns the byte of @('i') specified by @('bsp')." :long "<p>This is analogous to Common Lisp's @('(ldb bytespec integer)').</p>" :enabled t (loghead (bsp-size bsp) (logtail (bsp-position bsp) i)) /// (defthm unsigned-byte-p-rdb (implies (and (>= size (bsp-size bsp)) (force (>= size 0)) (force (integerp size)) (force (bspp bsp))) (unsigned-byte-p size (rdb bsp i)))) (defthm rdb-upper-bound (implies (force (bspp bsp)) (< (rdb bsp i) (expt 2 (bsp-size bsp)))) :rule-classes (:linear :rewrite)) (defthm bitp-rdb-bsp-1 (implies (equal (bsp-size bsp) 1) (bitp (rdb bsp i))) :hints (("Goal" :in-theory (enable bitp loghead)))))
other
(define wrb ((i integerp) (bsp bspp) (j integerp)) :returns (int integerp :rule-classes :type-prescription :name wrb-type) :parents (logops-byte-functions) :short "@(call wrb) writes the @('(bsp-size bsp)') low-order bits of @('i') into the byte of @('j') specified by @('bsp')." :long "<p>This is analogous to Common Lisp's @('(dpb newbyte bytespec integer)').</p>" :enabled t (logapp (bsp-position bsp) (loghead (bsp-position bsp) j) (logapp (bsp-size bsp) i (logtail (+ (bsp-size bsp) (bsp-position bsp)) j))))
other
(define rdb-test ((bsp bspp) (i integerp)) :returns bool :parents (logops-byte-functions) :short "@(call rdb-test) is true iff the field of @('i') specified by @('bsp') is nonzero." :long "<p>This is analogous to Common Lisp's @('(ldb-test bytespec integer)').</p>" :enabled t (not (eql (rdb bsp i) 0)))
other
(define rdb-field ((bsp bspp) (i integerp)) :returns nat :parents (logops-byte-functions) :short "@(call rdb-field) is analogous to Common Lisp's @('(mask-field bytespec integer)')." :enabled t (logand i (wrb -1 bsp 0)))
other
(define wrb-field ((i integerp) (bsp bspp) (j integerp)) :returns (int integerp :rule-classes :type-prescription :name wrb-field-type) :parents (logops-byte-functions) :short "@(call wrb-field) is analogous to Common Lisp's @('(deposit-field newbyte bytespec integer)')." :enabled t (wrb (rdb bsp i) bsp j))
other
(defsection rdb-guard :parents (logops-byte-functions) :short "@(call rdb-guard) is a macro form of the guards for @(see rdb), @(see rdb-test), and @(see rdb-field)." :long "@(def rdb-guard)" (defmacro rdb-guard (bsp i) `(and (force (bspp ,BSP)) (force (integerp ,I)))))
other
(defsection wrb-guard :parents (logops-byte-functions) :short "@(call wrb-guard) is a macro form of the guards for @(see wrb) and @(see wrb-field)." :long "@(def wrb-guard)" (defmacro wrb-guard (i bsp j) `(and (force (integerp ,I)) (force (bspp ,BSP)) (force (integerp ,J)))))
other
(defval *logops-functions* :parents (logops-definitions) :short "A list of all functions considered to be part of the theory of logical operations on numbers." '(binary-logior binary-logxor binary-logand binary-logeqv lognand lognor logandc1 logandc2 logorc1 logorc2 lognot logtest logbitp ash logcount integer-length bitp signed-byte-p unsigned-byte-p logcar$inline logcdr$inline logcons$inline logbit$inline logmask$inline logmaskp loghead$inline logtail$inline logapp logrpl logext logrev1 logrev$inline logsat lognotu$inline logextu$inline ashu lshu bspp bsp-size bsp-position rdb wrb rdb-test rdb-field wrb-field b-not$inline b-and$inline b-ior$inline b-xor$inline b-eqv$inline b-nand$inline b-nor$inline b-andc1$inline b-andc2$inline b-orc1$inline b-orc2$inline))
other
(defsection logops-functions :parents (logops-definitions) :short "A theory consisting of all function names of functions considered to be logical operations on numbers." :long "<p>If you are using the book @('logops-lemmas'), you will need to DISABLE this theory in order to use the lemmas contained therein, as most of the logical operations on numbers are non-recursive.</p>" (deftheory logops-functions *logops-functions*))
other
(defsection logops-definitions-theory :parents (logops-definitions) :short "The "minimal" theory for the book "logops-definitions"." :long "<p>This theory contains the DEFUN-TYPE/EXEC-THEORY (which see) of all functions considered to be logical operations on numbers, and all lemmas (predominately `type lemmas') proved in this book. All functions in the list *LOGOPS-FUNCTIONS* are DISABLEd.</p>" (deftheory logops-definitions-theory (union-theories (set-difference-theories (set-difference-theories (universal-theory :here) (universal-theory 'begin-logops-definitions)) *logops-functions*) (defun-type/exec-theory *logops-functions*))))
other
(defsection defbytetype :parents (logops-definitions) :short "A macro for defining integer subrange types." :long "<p>The "byte types" defined by DEFBYTETYPE correspond to the Common Lisp concept of a "byte", that is, an integer with a fixed number of bits. We extend the Common Lisp concept to allow signed bytes.</p> <p>Example:</p> @({ (DEFBYTETYPE WORD 32 :SIGNED) }) <p>Defines a new integer type of 32-bit signed integers, recognized by @('(WORD-P i)').</p> <p>General Form:</p> @({ (DEFBYTETYPE name size s/u &key saturating-coercion) }) <p>The argument name should be a symbol, size should be a constant expression (suitable for DEFCONST) for a positive integer, s/u is either :SIGNED or :UNSIGNED, saturating-coercion should be a symbol (default NIL).</p> <p>Each data type defined by DEFBYTETYPE produces a number of events:</p> <ul> <li>A constant @('*<name>-MAX*'), set to the maximum value of the type.</li> <li>A constant @('*<name>-MIN*'), set to the minimum value of the type.</li> <li>A predicate, @('(<pred> x)'), that recognizes either @('(UNSIGNED-BYTE-P size x)') or @('(SIGNED-BYTE-P size x)'), depending on whether s/u was :UNSIGNED or :SIGNED respectively. This predicate is DISABLED. The name of the predicate will be @('<name>-p').</li> <li>A coercion function, @('(<name> i)'), that coerces any object @('i') to the correct type by LOGHEAD and LOGEXT for unsigned and signed integers respectively. This function is DISABLED.</li> <li>A lemma showing that the coercion function actually does the correct coercion.</li> <li>A lemma that reduces calls of the coercion function when its argument satisfies the predicate.</li> <li>A forward chaining lemma from the predicate to the appropriate type information.</li> <li>If :SATURATING-COERCION is specified, the value of this keyword argument should be a symbol. A function of this name will be defined to provide a saturating coercion. `Saturation' in this context means that values outside of the legal range for the type are coerced to the type by setting them to the nearest legal value, which will be either the minimum or maximum value of the type. This function will be DISABLEd, and a lemma will be generated that proves that this function returns the correct type. Note that the :SATURATING-COERCION option is only valid for :SIGNED types.</li> <li>A theory named @('<name>')-THEORY that includes the lemmas and the DEFUN-TYPE/EXEC-THEORY of the functions.</li> </ul>")
defbytetypemacro
(defmacro defbytetype (name size s/u &key saturating-coercion doc) (declare (xargs :guard (and (symbolp name) (or (eq s/u :signed) (eq s/u :unsigned)) (implies saturating-coercion (and (symbolp saturating-coercion) (eq s/u :signed))) (implies doc (stringp doc))))) (let* ((max-constant (pack-intern name "*" name "-MAX*")) (min-constant (pack-intern name "*" name "-MIN*")) (predicate (pack-intern name name "-P")) (predicate-lemma (pack-intern name predicate "-" name)) (coercion-lemma (pack-intern name "REDUCE-" name)) (forward-lemma (pack-intern predicate predicate "-FORWARD")) (sat-lemma (pack-intern name predicate "-" saturating-coercion)) (theory (pack-intern name name "-THEORY"))) `(encapsulate nil (local (in-theory (theory 'basic-boot-strap))) (local (in-theory (enable logops-definitions-theory))) (local (in-theory (enable loghead-identity logext-identity))) (defconst ,MAX-CONSTANT ,(CASE S/U (:SIGNED `(- (EXPT2 (- ,SIZE 1)) 1)) (:UNSIGNED `(- (EXPT2 ,SIZE) 1)))) (defconst ,MIN-CONSTANT ,(CASE S/U (:SIGNED `(- (EXPT2 (- ,SIZE 1)))) (:UNSIGNED 0))) (defun ,PREDICATE (x) (declare (xargs :guard t)) ,(CASE S/U (:SIGNED `(SIGNED-BYTE-P ,SIZE X)) (:UNSIGNED `(UNSIGNED-BYTE-P ,SIZE X)))) (defun ,NAME (i) ,@(WHEN$CL DOC (LIST DOC)) (declare (xargs :guard (integerp i))) ,(CASE S/U (:SIGNED `(LOGEXT ,SIZE I)) (:UNSIGNED `(LOGHEAD ,SIZE I)))) (defthm ,PREDICATE-LEMMA (,PREDICATE (,NAME i))) (defthm ,COERCION-LEMMA (implies (,PREDICATE i) (equal (,NAME i) i))) (defthm ,FORWARD-LEMMA (implies (,PREDICATE x) ,(CASE S/U (:SIGNED `(INTEGERP X)) (:UNSIGNED `(AND (INTEGERP X) (>= X 0))))) :rule-classes :forward-chaining) ,@(WHEN$CL SATURATING-COERCION (LIST `(DEFUN ,SATURATING-COERCION (I) (DECLARE (XARGS :GUARD (INTEGERP I))) (LOGSAT ,SIZE I)) `(DEFTHM ,SAT-LEMMA (,PREDICATE (,SATURATING-COERCION I))))) (in-theory (disable ,PREDICATE ,NAME ,@(WHEN$CL SATURATING-COERCION (LIST SATURATING-COERCION)))) (deftheory ,THEORY (union-theories (defun-type/exec-theory '(,PREDICATE ,NAME ,@(WHEN$CL SATURATING-COERCION (LIST SATURATING-COERCION)))) '(,PREDICATE-LEMMA ,COERCION-LEMMA ,FORWARD-LEMMA ,@(WHEN$CL SATURATING-COERCION (LIST SAT-LEMMA))))))))
defword-tuple-pfunction
(defun defword-tuple-p (tuple) (or (and (true-listp tuple) (or (equal (length tuple) 3) (equal (length tuple) 4)) (symbolp (first tuple)) (integerp (second tuple)) (> (second tuple) 0) (integerp (third tuple)) (>= (third tuple) 0) (implies (fourth tuple) (stringp (fourth tuple)))) (er hard 'defword "A field designator for DEFWORD must be a list, the first ~ element of which is a symbol, the second a positive integer, ~ and the third a non-negative integer. If a fouth element is ~ provided it must be a string. This object violates these ~ constraints: ~p0" tuple)))
defword-tuple-p-listpfunction
(defun defword-tuple-p-listp (struct) (cond ((null struct) t) (t (and (defword-tuple-p (car struct)) (defword-tuple-p-listp (cdr struct))))))
defword-struct-pfunction
(defun defword-struct-p (struct) (cond ((true-listp struct) (defword-tuple-p-listp struct)) (t (er hard 'defword "The second argument of DEFWORD must be a true list. ~ This object is not a true list: ~p0" struct))))
defword-guardsfunction
(defun defword-guards (name struct conc-name set-conc-name keyword-updater doc) (and (or (symbolp name) (er hard 'defword "The name must be a symbol. This is not a symbol: ~p0" name)) (defword-struct-p struct) (or (symbolp conc-name) (er hard 'defword "The :CONC-NAME must be a symbol. This is not a symbol: ~ ~p0" conc-name)) (or (symbolp set-conc-name) (er hard 'defword "The :SET-CONC-NAME must be a symbol. This is not a symbol: ~ ~p0" conc-name)) (or (symbolp keyword-updater) (er hard 'defword "The :KEYWORD-UPDATER must be a symbol. This is not a symbol: ~ ~p0" conc-name)) (or (implies doc (stringp doc)) (er hard 'defword "The :DOC must be a string. This is not a string: ~p0" doc))))
defword-accessor-namefunction
(defun defword-accessor-name (name conc-name field) (pack-intern name conc-name field))
defword-updater-namefunction
(defun defword-updater-name (name set-conc-name field) (pack-intern name set-conc-name field))
defword-accessor-definitionsfunction
(defun defword-accessor-definitions (rdb name conc-name tuples) (cond ((consp tuples) (let* ((tuple (car tuples)) (field (first tuple)) (size (second tuple)) (pos (third tuple)) (doc (fourth tuple)) (accessor (defword-accessor-name name conc-name field))) (cons `(defmacro ,ACCESSOR (word) ,@(IF DOC (LIST DOC) NIL) (list ',RDB (list 'bsp ,SIZE ,POS) word)) (defword-accessor-definitions rdb name conc-name (cdr tuples))))) (t nil)))
defword-updater-definitionsfunction
(defun defword-updater-definitions (wrb name set-conc-name tuples) (cond ((consp tuples) (let* ((tuple (car tuples)) (field (first tuple)) (size (second tuple)) (pos (third tuple)) (updater (defword-updater-name name set-conc-name field))) (cons `(defmacro ,UPDATER (val word) (list ',WRB val (list 'bsp ,SIZE ,POS) word)) (defword-updater-definitions wrb name set-conc-name (cdr tuples))))) (t nil)))
other
(defloop defword-keyword-field-alist
(name set-conc-name field-names)
(for ((field-name in field-names))
(collect (cons (intern-in-package-of-symbol (string field-name) :keyword)
(defword-updater-name name set-conc-name field-name)))))
defword-keyword-updater-bodyfunction
(defun defword-keyword-updater-body (val args keyword-field-alist) (cond ((atom args) val) (t `(,(CDR (ASSOC (CAR ARGS) KEYWORD-FIELD-ALIST)) ,(CADR ARGS) ,(DEFWORD-KEYWORD-UPDATER-BODY VAL (CDDR ARGS) KEYWORD-FIELD-ALIST)))))
defword-keyword-updater-fnfunction
(defun defword-keyword-updater-fn (form val args keyword-updater keyword-field-alist) (declare (xargs :mode :program)) (let* ((keyword-field-names (strip-cars keyword-field-alist))) (cond ((not (keyword-value-listp args)) (er hard keyword-updater "The argument list in the macro invocation ~p0 ~ does not match the syntax of a keyword argument ~ list because ~@1." form (reason-for-non-keyword-value-listp args))) ((not (subsetp (evens args) keyword-field-names)) (er hard keyword-updater "The argument list in the macro invocation ~p0 is not ~ a valid keyword argument list because it contains the ~ ~#1~[keyword~/keywords~] ~&1, which ~#1~[is~/are~] ~ not the keyword ~#1~[form~/forms~] of any of the ~ field names ~&2." form (set-difference-equal (evens args) keyword-field-names) keyword-field-names)) (t (defword-keyword-updater-body val args keyword-field-alist)))))
defword-keyword-updaterfunction
(defun defword-keyword-updater (name keyword-updater set-conc-name field-names) `(defmacro ,KEYWORD-UPDATER (&whole form val &rest args) (defword-keyword-updater-fn form val args ',KEYWORD-UPDATER ',(DEFWORD-KEYWORD-FIELD-ALIST NAME SET-CONC-NAME FIELD-NAMES))))
other
(defsection defword :parents (logops-definitions) :short "A macro to define packed integer data structures." :long "<p>Example:</p> @({ (DEFWORD FM9001-INSTRUCTION-WORD ((RN-A 4 0) (MODE-A 2 4) (IMMEDIATE 9 0) (A-IMMEDIATE 1 9) (RN-B 4 10) (MODE-B 2 14) (SET-FLAGS 4 16) (STORE-CC 4 20) (OP-CODE 4 24)) :CONC-NAME || :SET-CONC-NAME SET-) }) <p>The above example defines the instruction word layout for the FM9001. The macro defines accessing macros (RN-A i), ... ,(OP-CODE i), updating macros (SET-RN-A val i), ... ,(SET-OP-CODE val i), and a keyword updating macro @('(UPDATE-FM9001-INSTRUCTION-WORD val &rest args)').</p> <p>General form:</p> @({ (DEFWORD name struct &key conc-name set-conc-name keyword-updater) }) <p>The DEFWORD macro defines a packed integer data structure, for example an instruction word for a programmable processor or a status word. DEFWORD is a simple macro that defines accessing and updating macros for the fields of the data structure. The utility of DEFWORD is mainly to simplify the specification of packed integer data structures, and to improve the readability of code manipulating these data structures without affecting performance. As long as the book "logops-lemmas" is loaded all of the important facts about the macro expansions should be available to the theorem prover.</p> <p>Arguments</p> @({ name: The name of the data structure, a symbol. struct : The field structure of the word. The form of this argument is given by the following grammar: <tuple> := (<field> <size> <pos> [ <doc> ]) <struct> := () | (<tuple> . <struct>) where: (SYMBOLP <field>) (AND (INTEGERP <size>) (> <size> 0)) (AND (INTEGERP <pos>) (>= <pos> 0)) (STRINGP <doc>) }) <p>In other words, a list of tuples, the first element being a symbol, the second a positive integer, the third a nonnegative integer, and the optional fourth a string.</p> <p>Note that there are few other requirements on the @('<struct>') other than the syntactic ones above. For example, the FM9001 DEFWORD shows that a word may have more than one possible structure - the first 9 bits of the FM9001 instruction word are either an immediate value, or they include the RN-A and MODE-A fields.</p> <p>conc-name, set-conc-name: These are symbols whose print names will be concatenated with the field names to produce the name of the accessors and updaters respectively. The default is @('<name>')- and @('SET-<name>')- respectively. The access and update macro names will be interned in the package of name.</p> <p>keyword-updater: This is a symbol, and specifies the name of the keyword updating macro (see below). The default is @('UPDATE-<name>').</p> <h3>Interpretation</h3> <p>DEFWORD creates an ACL2 DEFLABEL event named @('<name>').</p> <p>Each tuple @('(<field> <size> <pos>)') represents a @('<size>')-bit field of a word at the bit position indicated. Each field tuple produces an accessor macro</p> @({ (<accessor> word) }) <p>where @('<accessor>') is computed from the :conc-name (see above). This accessor will expand into:</p> @({ (RDB (BSP <size> <pos>) word). }) <p>DEFWORD also generates an updating macro</p> @({ (<updater> val word) }) <p>where @('<updater>') is computed from the :set-conc-name (see above). This macro will expand to</p> @({ (WRB val (BSP <size> <pos>) word) }) <p>The keyword updater</p> @({ (<keyword-updater> word &rest args) }) <p>is equivalent to multiple nested calls of the updaters on the initial word. For example,</p> @({ (UPDATE-FM9001-INSTRUCTION-WORD WORD :RN-A 10 :RN-B 12) }) <p>is the same as @('(SET-RN-A 10 (SET-RN-B 12 WORD))').</p>")
defwordmacro
(defmacro defword (name struct &key conc-name set-conc-name keyword-updater doc) (cond ((not (defword-guards name struct conc-name set-conc-name keyword-updater doc))) (t (let* ((conc-name (if conc-name conc-name (pack-intern name name "-"))) (set-conc-name (if set-conc-name set-conc-name (pack-intern name "SET-" name "-"))) (keyword-updater (if keyword-updater keyword-updater (pack-intern name "UPDATE-" name))) (accessor-definitions (defword-accessor-definitions 'rdb name conc-name struct)) (updater-definitions (defword-updater-definitions 'wrb name set-conc-name struct)) (field-names (strip-cars struct))) `(encapsulate nil (deflabel ,NAME ,@(IF DOC `(:DOC ,DOC) NIL)) ,@ACCESSOR-DEFINITIONS ,@UPDATER-DEFINITIONS ,(DEFWORD-KEYWORD-UPDATER NAME KEYWORD-UPDATER SET-CONC-NAME FIELD-NAMES))))))
other
(defxdoc word/bit-macros :parents (logops-definitions) :short "Macros for manipulating integer words defined as contiguous bits." :long "<p>These macros were defined to support the functions produced by translating SPW .eqn files to ACL2 functions.</p>")
bind-word-to-bits-fnfunction
(defun bind-word-to-bits-fn (bit-names n word) (cond ((endp bit-names) nil) (t (cons `(,(CAR BIT-NAMES) (logbit ,N ,WORD)) (bind-word-to-bits-fn (cdr bit-names) (1+ n) word)))))
other
(defsection bind-word-to-bits :parents (word/bit-macros) :short "Bind variables to the contiguous low-order bits of word." :long "<p>Example:</p> @({ (BIND-WORD-TO-BITS (A B C) I (B-AND A (B-IOR B C))) }) <p>The above macro call will bind A, B, and C to the 0th, 1st, and 2nd bit of I, and then evaluate the logical expression under those bindings. The list of bit names is always interpreted from low to high order.</p>" (defmacro bind-word-to-bits (bit-names word &rest forms) (declare (xargs :guard (and (symbol-listp bit-names) (no-duplicatesp bit-names)))) `(let ,(BIND-WORD-TO-BITS-FN BIT-NAMES 0 WORD) ,@FORMS)))
other
(defsection make-word-from-bits :parents (word/bit-macros) :short "Update the low-order bits of word with the indicated values." :long "<p>Example:</p> @({ (MAKE-WORD-FROM-BITS A B C) }) <p>The above macro call will build an unsigned integer from the bits A B, and C. The list of bits is always interpreted from low to high order. Note that the expression generated by this macro will coerce the values to bits before building the word.</p>" (defmacro make-word-from-bits (&rest bits) (cond ((endp bits) 0) (t `(logapp 1 ,(CAR BITS) (make-word-from-bits ,@(CDR BITS)))))))