src/wam/constants.lisp @ 72bbdd515725

Rewrite the compiler

A few days ago I found a bug in the compiler that I decided merited basically an
entire rewrite of it.

This was long overdue.  The compiler kind of grew organically and unhealthily
over time as I wrapped my head around how the whole WAM is structured, and now
that I understand a lot more I can do things right.

This new implementation is a lot "flatter" than the old one.  It makes use of
CLOS classes and generic methods to un-nest a lot of the crap that was
previously happening in bigass `labels` blocks.  This is a lot easier to read
and understand because you can take things a piece at a time.

Unfortunately, it's currently a lot slower than the old one.  But at least it's
*correct*, and now I can start taking a look at optimizing the performance with
a cleaner base to start from.

Notes/ideas for the near future:

* Switch to structs instead of CLOS classes for all the bits and bobs in the
  compilation process.
* Inline hot functions in the compilation process.
* Type hint the fucking compiler already.  I've put this off for far too long.
* Move the compiler to its own package for easier profiling and to maintain my
  shreds of sanity.
* Look into that generic-function-inlining library thing I saw on Reddit...
* Remove the last vestiges of `match` and kill the dependency on optima.
author Steve Losh <steve@stevelosh.com>
date Tue, 07 Jun 2016 14:49:20 +0000
parents e244881864f7
children 792dfa2f9120
(in-package #:bones.wam)

(define-constant +cell-width+ 16
  :documentation "Number of bits in each cell.")

(define-constant +cell-tag-width+ 3
  :documentation "Number of bits reserved for cell type tags.")

(define-constant +cell-value-width+ (- +cell-width+ +cell-tag-width+)
  :documentation "Number of bits reserved for cell values.")

(define-constant +cell-tag-bitmask+ #b111
  :documentation "Bitmask for masking the cell type tags.")


(define-constant +code-word-size+ 16
  :documentation "Size (in bits) of each word in the code store.")

(define-constant +code-limit+ (expt 2 +code-word-size+)
  :documentation "Maximum size of the WAM code store.")

(define-constant +code-sentinel+ (1- +code-limit+)
  ; TODO: Should this sentinel value be 0 like everything else?
  :documentation "Sentinel value used in the PC and CP.")


(define-constant +tag-null+      #b000
  :documentation "An empty cell.")

(define-constant +tag-structure+ #b001
  :documentation "A structure cell.")

(define-constant +tag-reference+ #b010
  :documentation "A pointer to a cell.")

(define-constant +tag-functor+   #b011
  :documentation "A functor.")

(define-constant +tag-constant+  #b100
  :documentation "A constant (i.e. a 0-arity functor).")

(define-constant +tag-list+  #b101
  :documentation "A Prolog list.")


(define-constant +register-count+ 2048
  :documentation "The number of local registers the WAM has available.")


(define-constant +maximum-arity+ 1024
  :documentation "The maximum allowed arity of functors.")

(define-constant +maximum-query-size+ 1024
  :documentation
  "The maximum size (in bytes of bytecode) a query may compile to.")


(define-constant +stack-limit+ 2048
  :documentation "Maximum size of the WAM stack.")

(define-constant +stack-frame-size-limit+ (+ 7 +register-count+)
  :documentation "The maximum size, in stack frame words, that a stack frame could be.")


(define-constant +stack-start+ +register-count+
  :documentation "The address in the store of the first cell of the stack.")

(define-constant +stack-end+ (+ +stack-start+ +stack-limit+)
  :documentation
  "The address in the store one past the last cell in the stack.")

(define-constant +heap-start+ +stack-end+
  :documentation "The address in the store of the first cell of the heap.")

(define-constant +trail-limit+ (expt 2 +cell-width+)
  ;; The trail's fill pointer is stored inside choice frames on the stack, so it
  ;; needs to be able to fit inside a stack word.  We don't tag it, though, so
  ;; we can technically use all of the cell bits if we want.
  ;;
  ;; TODO: should probably limit this to something more reasonable
  :documentation "The maximum number of variables that may exist in the trail.")


(define-constant +store-limit+ (expt 2 +cell-value-width+)
  ;; Reference cells need to be able to store a heap address in their value
  ;; bits, so that limits the amount of addressable space we've got to work
  ;; with.
  :documentation "Maximum size of the WAM store.")

(define-constant +heap-limit+ (- +store-limit+ +register-count+ +stack-limit+)
  ;; The heap gets whatever's left over after the registers and stack have taken
  ;; their chunk of memory.
  :documentation "Maximum size of the WAM heap.")


(define-constant +functor-limit+ (expt 2 +cell-value-width+)
  ;; Functors are referred to by their index into the functor array.  This index
  ;; is stored in the value part of functor cells.
  :documentation "The maximum number of functors the WAM can keep track of.")


;;;; Opcodes
(define-constant +opcode-noop+ 0)


;;; Program
(define-constant +opcode-get-structure+ 1)
(define-constant +opcode-unify-variable-local+ 2)
(define-constant +opcode-unify-variable-stack+ 3)
(define-constant +opcode-unify-value-local+ 4)
(define-constant +opcode-unify-value-stack+ 5)
(define-constant +opcode-get-variable-local+ 6)
(define-constant +opcode-get-variable-stack+ 7)
(define-constant +opcode-get-value-local+ 8)
(define-constant +opcode-get-value-stack+ 9)


;;; Query
(define-constant +opcode-put-structure+ 10)
(define-constant +opcode-set-variable-local+ 11)
(define-constant +opcode-set-variable-stack+ 12)
(define-constant +opcode-set-value-local+ 13)
(define-constant +opcode-set-value-stack+ 14)
(define-constant +opcode-put-variable-local+ 15)
(define-constant +opcode-put-variable-stack+ 16)
(define-constant +opcode-put-value-local+ 17)
(define-constant +opcode-put-value-stack+ 18)


;;; Control
(define-constant +opcode-call+ 19)
(define-constant +opcode-proceed+ 20)
(define-constant +opcode-allocate+ 21)
(define-constant +opcode-deallocate+ 22)
(define-constant +opcode-done+ 23)
(define-constant +opcode-try+ 24)
(define-constant +opcode-retry+ 25)
(define-constant +opcode-trust+ 26)
(define-constant +opcode-cut+ 27)


;;; Constants
(define-constant +opcode-get-constant+ 28)
(define-constant +opcode-set-constant+ 29)
(define-constant +opcode-put-constant+ 30)
(define-constant +opcode-unify-constant+ 31)

;;; Lists
(define-constant +opcode-get-list+ 32)
(define-constant +opcode-put-list+ 33)


;;;; Debug Config
(defparameter *off-by-one* nil)