other
(in-package "GL")
other
(include-book "gobject-types")
other
(include-book "../misc/numlist")
other
(include-book "std/util/bstar" :dir :system)
other
(program)
other
(defxdoc auto-bindings :parents (reference shape-specs) :short "Simplified shape specifiers for @(':g-bindings')." :long "<p>The @('auto-bindings') function lets you create simple @(see shape-specs) in an easy way. Here is an example:</p> @({ (def-gl-thm foo ... :g-bindings (auto-bindings ; expands to: (:nat opcode 8) ; g-integer with indices 0-8 (:int multiplier 16) ; g-integer with indices 9-25 (:bool enable) ; g-boolean with index 26 (:mix (:nat a-bus 128) ; } g-integers whose indices are interleaved, (:nat b-bus 128) ; } 27 to 414 -- see below (:rev (:seq (:nat c-bus 64) ; } (:skip 64)))) ; } (:rev (:nat fixup-bits 4)) ; g-integer with indices 420-415 )) }) <p>This is good because</p> <ul> <li>you don't have to think about sign bits and do a bunch of stupid arithmetic to figure out the next free index, and</li> <li>you can painlessly extend the bindings when you want to add a new variable without having to update a bunch of indices.</li> </ul> <p>Auto-bindings are more limited than shape-specs. Except for the special @(':mix') command, you can only write:</p> @({ (:bool var) -- expands to a g-boolean shape-specifier (:int var n) -- expands to a g-integer with n bits (signed 2's complement) (:nat var n) -- equivalent to (:int var (+ 1 n)) (:skip n) -- takes up space in a :mix, but doesn't generate bindings. }) <p>The @(':rev') command reverses the order of the bits produced by directives inside it.</p> <p>The @(':mix') command interleaves the bits of the elements inside it. Currently we only allow mix to contain elements that are all the same size.</p> <p>The @(':seq') and @(':mix') commands can be nested to produce complicated interleavings.</p> <p>The @(':skip') command can be used to pad out a @(':mix') command so as to interleave a shorter variable with part of a longer variable. E.g.:</p> @({ (:mix (:int a 7) (:seq (:int b 4) (:skip 3))) }) <p>produces</p> @({ ((A (:G-INTEGER 0 2 4 6 8 9 10)) (B (:G-INTEGER 1 3 5 7))) }) <p>That is, the first part of @('a') is mixed with @('b') but once the bits of @('b') run out, the rest of the bits of @('a') are simply in sequence.</p> ")
other
(defxdoc flex-bindings :parents (reference shape-specs) :short "Shape specifiers for @(':g-bindings'), more flexible than @(see auto-bindings)." :long "<p>The @('flex-bindings') function lets you create somewhat more complicated @(see shape-specs) than is possible with @(see auto-bindings). We assume familiarity with @(see auto-bindings) in this documentation. The specific feature @('flex-bindings') offers that auto-bindings does not is the ability to split an integer variable into segments and generate indices for each segment independently.</p> @({ (def-gl-thm foo ... :g-bindings (flex-bindings ; expands to: ;; auto-bindings list -- generates indices ((:int a1 10) (:rev (:mix (:int a2 13) (:int b1 13))) (:int b2 10)) :arrange ;; generate shape spec bindings from the indices ((:int a a1 a2) ;; a is a g-integer, indices are a1's appended to a2's (:int b b1 b2)))) }) <p>The first argument is just a list of auto-bindings (though the syntax differs trivially in that flex-bindings takes them in a single argument whereas @(see auto-bindings) uses @('&rest args')). They are used to generate indices, but not the actual g-bindings. We generate from these a mapping from each variable name to its list of indices.</p> <p>The @(':arrange') argument, if provided, must be a list consisting of the following sorts of forms: </p> <ul> <li>@('(:int a b c ...)') means generate an integer shape-spec binding for variable @('a'), consisting of the appended indices of @('b'), @('c'), etc., from the auto-bindings form.</li> <li>@('(:int a)') means generate an integer shape-spec binding for variable @('a') using the indices of @('a') from the auto-bindings form.</li> <li>@('(:bool a)') means generate a Boolean binding for variable @('a'), using the index of @('a') from the auto-bindings form.</li> <li>@('(:bool a b)') means generate a Boolean binding for variable @('a'), using the index of @('b') from the auto-bindings form.</li> </ul> <p>If the @(':arrange') argument is not provided, @(see flex-bindings) acts just like @(see auto-bindings) -- it generates an entry for each variable mentioned in the auto-bindings.</p>")
ab-all-equalfunction
(defun ab-all-equal (x val) (if (atom x) t (and (equal (car x) val) (ab-all-equal (cdr x) val))))
other
(mutual-recursion (defun auto-bind-len (x) (case (first x) (:bool 1) (:int (third x)) (:rev (auto-bind-len (cadr x))) (:skip (second x)) (t (ab-sum (auto-bind-len-list (cdr x)))))) (defun auto-bind-len-list (x) (if (atom x) nil (cons (auto-bind-len (car x)) (auto-bind-len-list (cdr x))))))
other
(mutual-recursion (defun auto-bind-xlate (x inside-mix-p) (if (not (true-listp x)) (er hard? 'auto-bind-xlate "Auto-binding not even a true-listp: ~x0" x) (case (first x) (:bool (cond (inside-mix-p (er hard? 'auto-bind-xlate "Auto-bindings of :bool aren't allowed directly inside mix: ~x0" x)) ((and (= (len x) 2) (legal-variablep (second x))) (list :bool (second x) 1)) (t (er hard? 'auto-bind-xlate "Auto-binding is invalid: ~x0" x)))) ((:nat :int) (if (and (= (len x) 3) (legal-variablep (second x)) (natp (third x))) (list :int (second x) (if (eq (first x) :nat) (+ 1 (third x)) (third x))) (er hard? 'auto-bind-xlate "Auto-binding is invalid: ~x0" x))) (:mix (b* (((unless (<= 3 (len x))) (er hard? "Auto-binding is invalid: mix with too few elements: ~x0" x)) (elems (auto-bind-xlate-list (cdr x) t)) (lens (auto-bind-len-list elems)) ((unless (ab-all-equal (cdr lens) (car lens))) (er hard? 'auto-bind-xlate "Lengths inside :mix must agree: ~x0 has lengths ~x1" elems lens))) (cons :mix elems))) (:seq (cons :seq (auto-bind-xlate-list (cdr x) nil))) (:rev (cond ((= (len x) 2) (list :rev (auto-bind-xlate (cadr x) inside-mix-p))) (t (er hard? 'auto-bind-xlate "Auto-binding is invalid: ~x0" x)))) (:skip (if (and (= (len x) 2) (natp (second x))) x (er hard? 'auto-bind-xlate "Auto-binding is invalid: ~x0" x))) (otherwise (er hard? 'auto-bind-xlate "Auto-binding has unrecognized type: ~x0" x))))) (defun auto-bind-xlate-list (x inside-mix-p) (if (atom x) nil (cons (auto-bind-xlate (car x) inside-mix-p) (auto-bind-xlate-list (cdr x) inside-mix-p)))))
other
(mutual-recursion (defun auto-bind-generate (x free-idx by) (case (car x) ((:bool :int) (b* (((list type var len) x)) (list (cons var (if (eq type :bool) (list free-idx) (numlist free-idx by len)))))) (:rev (let ((len (auto-bind-len (cadr x)))) (auto-bind-generate (cadr x) (+ free-idx (* by (1- len))) (- by)))) (:mix (auto-bind-generate-mix (cdr x) free-idx by (* by (len (cdr x))))) (:seq (auto-bind-generate-seq (cdr x) free-idx by)) (:skip nil) (otherwise (er hard? 'auto-bind-generate "Should never happen: not translated: ~x0" x)))) (defun auto-bind-generate-mix (x free-idx interleave-by inner-by) (if (atom x) nil (append (auto-bind-generate (car x) free-idx inner-by) (auto-bind-generate-mix (cdr x) (+ free-idx interleave-by) interleave-by inner-by)))) (defun auto-bind-generate-seq (x free-idx by) (if (atom x) nil (append (auto-bind-generate (car x) free-idx by) (auto-bind-generate-seq (cdr x) (+ (* by (auto-bind-len (car x))) free-idx) by)))))
other
(mutual-recursion (defun auto-bind-skips (x free-idx by) (case (car x) ((:bool :int) nil) (:rev (let ((len (auto-bind-len (cadr x)))) (auto-bind-skips (cadr x) (+ free-idx (* by (1- len))) (- by)))) (:mix (auto-bind-skips-mix (cdr x) free-idx by (* by (len (cdr x))))) (:seq (auto-bind-skips-seq (cdr x) free-idx by)) (:skip (numlist free-idx by (cadr x))) (otherwise (er hard? 'auto-bind-generate "Should never happen: not translated: ~x0" x)))) (defun auto-bind-skips-mix (x free-idx interleave-by inner-by) (if (atom x) nil (append (auto-bind-skips (car x) free-idx inner-by) (auto-bind-skips-mix (cdr x) (+ free-idx interleave-by) interleave-by inner-by)))) (defun auto-bind-skips-seq (x free-idx by) (if (atom x) nil (append (auto-bind-skips (car x) free-idx by) (auto-bind-skips-seq (cdr x) (+ (* by (auto-bind-len (car x))) free-idx) by)))))
auto-bind-index-mapfunction
(defun auto-bind-index-map (n skiptable len offset acc) (if (mbe :logic (zp (- (nfix len) (nfix n))) :exec (eql n len)) acc (if (hons-get n skiptable) (auto-bind-index-map (1+ (lnfix n)) skiptable len (1+ offset) acc) (auto-bind-index-map (1+ (lnfix n)) skiptable len offset (hons-acons n (- n offset) acc)))))
auto-bind-remap-indices-listfunction
(defun auto-bind-remap-indices-list (x indexmap) (b* (((when (atom x)) nil) (look (hons-get (car x) indexmap)) ((unless look) (er hard? 'auto-bind-remap-index-list "Auto-bindings programming error: skipped index is present in auto-bindings"))) (cons (cdr look) (auto-bind-remap-indices-list (cdr x) indexmap))))
auto-bind-remap-indices-tablefunction
(defun auto-bind-remap-indices-table (x indexmap) (if (atom x) nil (cons (cons (caar x) (auto-bind-remap-indices-list (cdar x) indexmap)) (auto-bind-remap-indices-table (cdr x) indexmap))))
flex-bindings-append-auto-varsfunction
(defun flex-bindings-append-auto-vars (vars auto-alist) (if (atom vars) nil (append (b* ((auto-look (assoc (car vars) auto-alist)) ((unless auto-look) (er hard? 'flex-bindings-arrange "Missing auto-binding for ~x0" (car vars)))) (cdr auto-look)) (flex-bindings-append-auto-vars (cdr vars) auto-alist))))
flex-bindings-arrange1function
(defun flex-bindings-arrange1 (x auto-alist) (b* (((when (atom x)) (er hard? 'flex-bindings-arrange "Invalid arrange-list entry: ~x0" x)) ((cons key args) x) ((unless (and (consp args) (symbol-listp args) (not (member nil args)))) (er hard? 'flex-bindings-arrange "Invalid arrange-list entry: ~x0 -- args must be a ~ nonempty list of nonnil symbols" x))) (case key (:bool (b* ((len (len args)) ((unless (or (eql len 1) (eql len 2))) (er hard? 'flex-bindings-arrange "Invalid arrange-list entry: ~x0" x)) (varname (first args)) (autoname (if (eql len 2) (second args) (first args))) (auto-look (assoc autoname auto-alist)) ((unless auto-look) (er hard? 'flex-bindings-arrange "Missing auto-binding for ~x0" autoname)) (indices (cdr auto-look)) ((unless (eql (len indices) 1)) (er hard? 'flex-bindings-arrange "Boolean ~x0 assigned to wide auto-binding variable ~x1" varname autoname))) (list varname (g-boolean (car indices))))) (:int (b* ((len (len args)) (varname (car args)) (auto-vars (if (eql len 1) args (cdr args)))) (list varname (g-integer (flex-bindings-append-auto-vars auto-vars auto-alist))))) (otherwise (er hard? 'flex-bindings-arrange "Invalid arrange-list entry: ~x0 -- must begin with :bool or :int.")))))
flex-bindings-arrangefunction
(defun flex-bindings-arrange (arrange-list auto-alist) (if (atom arrange-list) nil (cons (flex-bindings-arrange1 (car arrange-list) auto-alist) (flex-bindings-arrange (cdr arrange-list) auto-alist))))
other
(mutual-recursion (defun auto-bindings-collect-arrange (x) (case (car x) ((:bool :int) (b* (((list type var) x)) (list (list type var)))) (:skip nil) (otherwise (auto-bindings-list-collect-arrange (cdr x))))) (defun auto-bindings-list-collect-arrange (x) (if (atom x) nil (append (auto-bindings-collect-arrange (car x)) (auto-bindings-list-collect-arrange (cdr x))))))
flex-bindings-fnfunction
(defun flex-bindings-fn (auto-bindings arrange-list start) (b* ((xlated-bindings (auto-bind-xlate-list auto-bindings nil)) (auto-alist (auto-bind-generate-seq xlated-bindings start 1)) (skips (auto-bind-skips-seq xlated-bindings start 1)) (skiptable (make-fast-alist (pairlis$ skips nil))) (indexmap (auto-bind-index-map 0 skiptable (ab-sum (auto-bind-len-list xlated-bindings)) 0 nil)) (auto-alist-remapped (auto-bind-remap-indices-table auto-alist indexmap)) (arrange-list (or arrange-list (auto-bindings-list-collect-arrange xlated-bindings)))) (flex-bindings-arrange arrange-list auto-alist-remapped)))
flex-bindingsmacro
(defmacro flex-bindings (auto-bindings &key arrange (start '0)) `(flex-bindings-fn ',GL::AUTO-BINDINGS ',GL::ARRANGE ,GL::START))
flex-param-bindingsfunction
(defun flex-param-bindings (in-alist) (b* (((when (atom in-alist)) nil) (case1 (car in-alist)) ((unless (and (true-listp case1) (or (eql (len case1) 2) (and (eql (len case1) 4) (eq (nth 2 case1) :arrange))))) (er hard? 'flex-param-bindings "Unsupported entry in flex-param-bindings: ~x0" case1)) ((list params auto-bindings ?arrange-keyword arrange) case1)) (cons (list params (flex-bindings-fn auto-bindings arrange 0)) (flex-param-bindings (cdr in-alist)))))
auto-bindings-fnfunction
(defun auto-bindings-fn (x) (flex-bindings-fn x nil 0))
auto-bindingsmacro
(defmacro auto-bindings (&rest args) `(auto-bindings-fn ',GL::ARGS))