1
;;=========================================================================
2
;; Copyright (C) 1999 Institut fuer Informatik, University of Kiel, Germany
3
;;===========================================================================
5
;; Author: Wolfgang Goerigk
6
;; Content: ACL2 implementation of a simple abstract machine
7
;; as of: 14/04/99, University of Texas at Austin, Texas, U.S.A.
8
;;---------------------------------------------------------------------------
10
;; $Id: machine.lisp,v 1.4 1999/09/26 11:28:16 wg Exp wg $
11
;;===========================================================================
12
;; This book is free software; you can redistribute it and/or modify it under
13
;; the terms of the GNU General Public License as published by the Free
14
;; Software Foundation; either version 2 of the License, or (at your option)
16
;;---------------------------------------------------------------------------
17
;; This book is distributed in the hope that it will be useful, but WITHOUT
18
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21
;;---------------------------------------------------------------------------
22
;; You should have received a copy of the GNU General Public License along
23
;; with this book; if not, write to the Free Software Foundation, Inc., 675
24
;; Mass Ave, Cambridge, MA 02139, USA.
25
;;===========================================================================
27
;; This book is part of a series of books that come with and are described in
28
;; the article "Wolfgang Goerigk: Compiler Verification Revisited" as part of
29
;; "Computer Aided Reasoning: ACL2 Case Studies" edited by Matt Kaufmann, Pete
30
;; Manolios and J Strother Moore.
32
;;===========================================================================
34
;; The Abstract Stack Machine
35
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~
36
;; This book defines the executable ACL2 model of an abstract stack machine
37
;; and the machine code (TL) used as target code for the compilers in the book
40
;;===========================================================================
43
(include-book "../../../ordinals/e0-ordinal")
44
(set-well-founded-relation e0-ord-<)
46
;;===========================================================================
47
;; We use our own version of butlast and call it butlst.
48
;;---------------------------------------------------------------------------
51
(declare (xargs :guard (true-listp x)))
55
(cons (car x) (butlst (cdr x)))
60
;;===========================================================================
61
;; The Abstract Machine (Program Semantics)
62
;;===========================================================================
64
;; Abstract Machine Programs:
65
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~
66
;; prog == (decl_1 ... decl_n (instr_1 ... instr_k))
67
;; decl == (DEFCODE <name> (instr_1 ... instr_k))
69
;; where in both cases n >= 0 and instructions are as defined below.
71
;; Abstract Machine Configuration:
72
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73
;; code == ((fn_1 . code_1) (fn_2 . code_2) ... (fn_n . code_n))
74
;; stack == (top top_1 top_2 ... bottom)
76
;; Operator calls including calls of user defined procedures consume (pop)
77
;; their arguments from the stack and push their result on top of the
78
;; stack. Instructions are
80
;; Abstract Machine Instructions and Evaluation
81
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
82
;; (PUSHC <constant>) ; push <constant> onto the stack
83
;; (PUSHV <index>) ; push the value of the <index>'th stack cell
84
;; (CALL <name>) ; execute the code associated with <name> in code
85
;; (OPR <name>) ; execute the Lisp operator <name> on the stack
86
;; (IF <then> <else>) ; execute <else>, if top = nil, otherwise <then>
87
;; (POP <n>) ; (top d1 ... dn . rest) -> (top . rest)
89
;; The functions mstep executes a single instruction, applied to the stack and
90
;; returning the new stack. msteps executes a sequence of instructions by
91
;; subsequently executing each of them.
93
;; Since in general machine programs may not terminate, an additional
94
;; <number-of-steps> argument (n) forces execution to terminate. Actually, we
95
;; decrease n only if a user defined subroutine is called, i.e. if we start to
96
;; execute its body. This is sufficient to guarantee termination since it is
97
;; the only case, where a structural induction would fail. So the measure
98
;; functions we use to admit mstep and msteps are (cons (1+ (acl2-count n))
99
;; (acl2-count form)) and (cons (1+ (acl2-count n)) (acl2-count seq)), i.e. we
100
;; use the lexicographical ordering of the depth of the call-tree and the
101
;; complexity of the syntactical structure. Note that the 1+ is necessary for
102
;; these conses to be e0-ordinalp's.
104
;; The instruction (IF <then> <else>) assumes the condition's value on top of
105
;; stack. The abstract machine language has structured code. Operators are
106
;; those recognized by the function "operatorp" which is defined in
109
;;---------------------------------------------------------------------------
111
;;---------------------------------------------------------------------------
112
;; The Lisp operators
113
;; ~~~~~~~~~~~~~~~~~~
114
;; for simplicity we could just use the ACL2 functions that correspond to our
115
;; operators (see definition of operatorp in "compiler") in order to implement
116
;; the operators. However, we would not be able to verify the guards because
117
;; we can not guarantee that the machine program uses the operators within
118
;; their Common Lisp domains. Therefore we define our own functions but prove
119
;; them to be equal to the ACL2 versions. The former makes sure that we can
120
;; certify this book, whereas the latter makes sure that the machine (and
121
;; hence the evaluator and the compiler) do something reasonable.
125
(declare (xargs :guard t))
126
(if (or (consp x) (equal x nil)) (car x) nil))
129
(declare (xargs :guard t))
130
(if (or (consp x) (equal x nil)) (cdr x) nil))
132
(defmacro MCADR (X) (LIST 'MCAR (LIST 'MCDR X)))
133
(defmacro mcddr (X) (LIST 'MCDR (LIST 'MCDR X)))
134
(defmacro mcdar (X) (LIST 'MCDR (LIST 'MCAR X)))
135
(defmacro MCADDR (X) (LIST 'MCAR (LIST 'mcddr X)))
136
(defmacro MCADAR (X) (LIST 'MCAR (LIST 'mcdar X)))
137
(defmacro mcddar (X) (LIST 'MCDR (LIST 'mcdar X)))
138
(defmacro mcdddr (X) (LIST 'MCDR (LIST 'mcddr X)))
139
(defmacro MCADDAR (X) (LIST 'MCAR (LIST 'mcddar X)))
140
(defmacro MCADDDR (X) (LIST 'MCAR (LIST 'mcdddr X)))
143
(declare (xargs :guard t))
144
(if (acl2-numberp n) (1+ n) 1))
147
(declare (xargs :guard t))
148
(if (acl2-numberp n) (1- n) -1))
150
(defmacro MLEN (X) (LIST 'LEN X))
151
(defmacro MSYMBOLP (X) (LIST 'SYMBOLP X))
152
(defmacro MCONSP (X) (LIST 'CONSP X))
153
(defmacro MATOM (X) (LIST 'ATOM X))
154
(defmacro MCONS (X Y) (LIST 'CONS X Y))
155
(defmacro MEQUAL (X Y) (LIST 'EQUAL X Y))
158
(declare (xargs :guard t))
161
(MAPPEND (cdr x) y)))))
164
(declare (xargs :guard t))
166
((equal x (car l)) l)
167
(t (MMEMBER x (cdr l)))))
169
(defun MASSOC (x alist)
170
(declare (xargs :guard t))
171
(cond ((atom alist) nil)
172
((equal x (mcar (car alist))) (car alist))
173
(t (MASSOC x (cdr alist)))))
176
(declare (xargs :guard t))
177
(if (and (acl2-numberp x) (acl2-numberp y))
179
(if (acl2-numberp x) x
180
(if (acl2-numberp y) y
184
(declare (xargs :guard t))
185
(if (and (acl2-numberp x) (acl2-numberp y))
187
(if (acl2-numberp x) x
188
(if (acl2-numberp y) (- y)
192
(declare (xargs :guard t))
193
(if (and (acl2-numberp x) (acl2-numberp y))
197
;;---------------------------------------------------------------------------
198
;; As mentioned above, we now prove that the operators defined by functions
199
;; are actually as in ACL2, that is that they are equal to the corresponding
200
;; ACL2 functions. Then we disable them, because we don't want the prover to
201
;; look into our definitions but let it use what it knows about the original
202
;; ACL2 functions instead.
205
(defthm mcar-is-like-car (equal (MCAR x) (car x)))
206
(defthm mcdr-is-like-cdr (equal (MCDR x) (cdr x)))
207
(defthm m1+-is-like-1+ (equal (M1+ n) (1+ n)))
208
(defthm m1--is-like-1- (equal (M1- n) (1- n)))
209
(defthm mappend-is-like-append (equal (MAPPEND x y) (append x y)))
210
(defthm mmember-is-like-member (equal (MMEMBER x l) (member x l)))
211
(defthm massoc-is-like-assoc (equal (MASSOC x alist) (assoc x alist)))
212
(defthm m+-is-like-+ (equal (M+ x y) (+ x y)))
213
(defthm m--is-like-- (equal (M- x y) (- x y)))
214
(defthm m*-is-like-* (equal (M* x y) (* x y)))
216
(in-theory (disable MCAR MCDR M1+ M1- M+ M* M- MAPPEND MMEMBER MASSOC))
219
;;---------------------------------------------------------------------------
220
;; The next is to define some data types, that is to say recognizers for
221
;; programs, declaration lists, instructions and instruction-lists, and
222
;; code. This is to be able to express the guards we want to verify. The
223
;; syntax of machine programs and of the code part of the machine's
224
;; configuration are as in the comment at the beginning of this book.
228
(defun instructionp (form)
229
(declare (xargs :guard t))
232
(cond ((equal (car form) 'PUSHC) t)
233
((equal (car form) 'PUSHV) (natp (cadr form)))
234
((equal (car form) 'CALL) (symbolp (cadr form)))
235
((equal (car form) 'OPR) (symbolp (cadr form)))
236
((equal (car form) 'POP) (natp (cadr form)))
237
((equal (car form) 'IF)
238
(and (consp (cdr form))
239
(instruction-listp (cadr form))
241
(instruction-listp (caddr form))))
245
(defun instruction-listp (seq)
246
(declare (xargs :guard t))
248
(and (instructionp (car seq))
249
(instruction-listp (cdr seq)))
254
(declare (xargs :guard t))
255
(cond ((atom l) (equal l nil))
256
(t (and (consp (car l))
258
(instruction-listp (cdar l))
262
(declare (xargs :guard t))
264
(and (consp (car dcls))
265
(equal (caar dcls) 'DEFCODE)
267
(symbolp (cadar dcls))
269
(instruction-listp (caddar dcls))
274
(declare (xargs :guard t))
275
(and (true-listp prog)
276
(declsp (butlst prog))
277
(instruction-listp (car (last prog)))))
279
;;---------------------------------------------------------------------------
280
;; The function get-code returns the instruction list associated with f within
284
(defun get-code (f code)
285
(declare (xargs :guard (and (symbolp f) (alistp code))))
286
(cdr (assoc f code)))
289
;;---------------------------------------------------------------------------
290
;; We need the following three theorems in order to be able to verify the
294
(defthm codep-implies-good-code
295
(implies (codep l) (instruction-listp (cdr (assoc f l)))))
296
(defthm codep-implies-alistp
297
(implies (codep code) (alistp code)))
298
(defthm codep-implies-consp-assoc
299
(implies (and (codep l) (assoc sym l)) (consp (assoc sym l))))
302
;;===========================================================================
303
;; Now we may start and define the machine. opr applies an operator to the
304
;; topmost stack cell(s), mstep executes one instruction, msteps an
305
;; instruction sequence (see the comment at the beginning of this script).
308
(defun opr (op code stack)
309
(declare (ignore code)
310
(xargs :guard (true-listp stack)))
312
((equal op 'CAR) (cons (MCAR (car stack)) (cdr stack)))
313
((equal op 'CDR) (cons (MCDR (car stack)) (cdr stack)))
314
((equal op 'CADR) (cons (MCADR (car stack)) (cdr stack)))
315
((equal op 'CADDR) (cons (MCADDR (car stack)) (cdr stack)))
316
((equal op 'CADAR) (cons (MCADAR (car stack)) (cdr stack)))
317
((equal op 'CADDAR) (cons (MCADDAR (car stack)) (cdr stack)))
318
((equal op 'CADDDR) (cons (MCADDDR (car stack)) (cdr stack)))
319
((equal op '1-) (cons (M1- (car stack)) (cdr stack)))
320
((equal op '1+) (cons (M1+ (car stack)) (cdr stack)))
321
((equal op 'LEN) (cons (MLEN (car stack)) (cdr stack)))
322
((equal op 'SYMBOLP) (cons (MSYMBOLP (car stack)) (cdr stack)))
323
((equal op 'CONSP) (cons (MCONSP (car stack)) (cdr stack)))
324
((equal op 'ATOM) (cons (MATOM (car stack)) (cdr stack)))
325
((equal op 'CONS) (cons (MCONS (cadr stack) (car stack)) (cddr stack)))
326
((equal op 'EQUAL) (cons (MEQUAL (cadr stack) (car stack)) (cddr stack)))
327
((equal op 'APPEND) (cons (MAPPEND (cadr stack) (car stack)) (cddr stack)))
328
((equal op 'MEMBER) (cons (MMEMBER (cadr stack) (car stack)) (cddr stack)))
329
((equal op 'ASSOC) (cons (MASSOC (cadr stack) (car stack)) (cddr stack)))
330
((equal op '+) (cons (M+ (cadr stack) (car stack)) (cddr stack)))
331
((equal op '-) (cons (M- (cadr stack) (car stack)) (cddr stack)))
332
((equal op '*) (cons (M* (cadr stack) (car stack)) (cddr stack)))
333
((equal op 'LIST1) (cons (CONS (car stack) nil) (cdr stack)))
334
((equal op 'LIST2) (cons (CONS (cadr stack) (CONS (car stack) nil)) (cddr stack)))
340
(defun mstep (form code stack n)
341
(declare (xargs :measure (cons (1+ (acl2-count n)) (acl2-count form))
342
:guard (and (instructionp form) (codep code) (natp n))))
344
((or (zp n) (not (true-listp stack))) 'ERROR)
345
((equal (car form) 'PUSHC) (cons (cadr form) stack))
346
((equal (car form) 'PUSHV) (cons (nth (cadr form) stack) stack))
347
((equal (car form) 'CALL)
348
(msteps (cdr (assoc (cadr form) code)) code stack (1- n)))
349
((equal (car form) 'OPR) (opr (cadr form) code stack))
350
((equal (car form) 'IF)
352
(msteps (cadr form) code (cdr stack) n)
353
(msteps (caddr form) code (cdr stack) n)))
354
((equal (car form) 'POP) (cons (car stack) (nthcdr (cadr form) (cdr stack))))))
356
(defun msteps (seq code stack n)
357
(declare (xargs :measure (cons (1+ (acl2-count n)) (acl2-count seq))
358
:guard (and (instruction-listp seq) (codep code) (natp n))))
360
(cond ((or (zp n) (not (true-listp stack))) 'ERROR)
362
(t (msteps (cdr seq) code (mstep (car seq) code stack n) n))))
366
;;---------------------------------------------------------------------------
367
;; In order to download a machine program's subroutine definitions we have to
368
;; construct the code part of the machine configuration, which is a true
369
;; association list binding the procedure names to their instruction
370
;; sequences. That is we have get rid of the DEFCODE's and construct a true
373
;; ((DEFCODE f1 code1) (DEFCODE f2 code2) ...) ->
374
;; ((f1 . code1) (f2 . code2) ...)
377
(defun download (dcls)
378
(declare (xargs :guard (declsp dcls)))
380
(cons (cons (cadar dcls) (caddar dcls))
381
(download (cdr dcls)))
384
;;---------------------------------------------------------------------------
385
;; Execution of an abstract machine program is executing the top level
386
;; instruction sequence with the code (download (butlast prog 1)) and the
390
(defun execute (prog stack n)
391
(declare (xargs :guard (and (progp prog) (natp n))))
392
(let ((code (download (butlst prog))))
393
(msteps (car (last prog)) code stack n)))
395
;;===========================================================================
397
;; This finishes the definition of the abstract machine.
399
;; The following two theorems install the definitional equations of "mstep"
400
;; and "msteps" from the above mutual recursion as :definition rules.
402
;;---------------------------------------------------------------------------
405
(equal (msteps seq code stack n)
406
(cond ((or (zp n) (not (true-listp stack))) 'ERROR)
409
(cdr seq) code (mstep (car seq) code stack n) n))))
410
:rule-classes ((:definition
411
:clique (mstep msteps)
413
((msteps t nil nil nil) (mstep t nil nil nil)))))
417
(equal (mstep form code stack n)
419
((or (zp n) (not (true-listp stack))) 'ERROR)
420
((equal (car form) 'PUSHC) (cons (cadr form) stack))
421
((equal (car form) 'PUSHV) (cons (nth (cadr form) stack) stack))
422
((equal (car form) 'CALL)
423
(msteps (cdr (assoc (cadr form) code)) code stack (1- n)))
424
((equal (car form) 'OPR) (opr (cadr form) code stack))
425
((equal (car form) 'IF)
427
(msteps (cadr form) code (cdr stack) n)
428
(msteps (caddr form) code (cdr stack) n)))
429
((equal (car form) 'POP)
430
(cons (car stack) (nthcdr (cadr form) (cdr stack))))))
431
:rule-classes ((:definition
432
:clique (mstep msteps)
434
((msteps t nil nil nil) (mstep t nil nil nil)))))
437
;;---------------------------------------------------------------------------
438
;; Now, we may disable mstep and msteps.
441
(in-theory (disable mstep msteps))
443
;;---------------------------------------------------------------------------
444
;; The following function is used to suggest a combined computational and
445
;; structural induction on the termination argument n and the structural depth
446
;; of machine instructions and machine instruction sequences.
449
(defun machine-induction (flag x code stack n)
450
(declare (xargs :mode :logic
451
:measure (cons (1+ (acl2-count n)) (acl2-count x))))
452
(if (or (atom x) (zp n))
455
(if (equal (car x) 'CALL)
456
(machine-induction nil
457
(cdr (assoc (cadr x) code))
459
(if (equal (car x) 'IF)
460
(list (machine-induction nil
463
(machine-induction nil
466
(list code stack n)))
467
(list (machine-induction t (car x) code stack n)
468
(machine-induction nil (cdr x)
470
(mstep (car x) code stack n)