;;; Guile bytecode assembler

;;; Copyright (C) 2001, 2009-2023 Free Software Foundation, Inc.
;;;
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public
;;; License as published by the Free Software Foundation; either
;;; version 3 of the License, or (at your option) any later version.
;;;
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; Lesser General Public License for more details.
;;;
;;; You should have received a copy of the GNU Lesser General Public
;;; License along with this library; if not, write to the Free Software
;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

;;; Commentary:
;;;
;;; This module implements an assembler that creates an ELF image from
;;; bytecode assembly and macro-assembly.  The input can be given in
;;; s-expression form, like ((OP ARG ...) ...).  Internally there is a
;;; procedural interface, the emit-OP procedures, but that is not
;;; currently exported.
;;;
;;; "Primitive instructions" correspond to VM operations.  Assemblers
;;; for primitive instructions are generated programmatically from
;;; (instruction-list), which itself is derived from the VM sources.
;;; There are also "macro-instructions" like "label" or "load-constant"
;;; that expand to 0 or more primitive instructions.
;;;
;;; The assembler also handles some higher-level tasks, like creating
;;; the symbol table, other metadata sections, creating a constant table
;;; for the whole compilation unit, and writing the dynamic section of
;;; the ELF file along with the appropriate initialization routines.
;;;
;;; Most compilers will want to use the trio of make-assembler,
;;; emit-text, and link-assembly.  That will result in the creation of
;;; an ELF image as a bytevector, which can then be loaded using
;;; load-thunk-from-memory, or written to disk as a .go file.
;;;
;;; Code:

(define-module (system vm assembler)
  #:use-module (system base target)
  #:use-module (system base types internal)
  #:use-module (system vm dwarf)
  #:use-module (system vm elf)
  #:use-module (system vm linker)
  #:use-module (system syntax internal)
  #:use-module (language bytecode)
  #:use-module (rnrs bytevectors)
  #:use-module (ice-9 binary-ports)
  #:use-module (ice-9 vlist)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-9)
  #:use-module (srfi srfi-11)
  #:export (make-assembler

            (emit-receive* . emit-receive)
            (emit-mov* . emit-mov)
            (emit-fmov* . emit-fmov)

            emit-u64=?
            emit-u64<?
            emit-u64-imm<?
            emit-imm-u64<?
            emit-s64-imm=?
            emit-s64<?
            emit-s64-imm<?
            emit-imm-s64<?
            emit-f64=?
            emit-f64<?
            emit-=?
            emit-<?
            emit-arguments<=?
            emit-positional-arguments<=?
            emit-immediate-tag=?
            emit-heap-tag=?
            emit-eq?
            emit-eq-immediate?
            emit-heap-numbers-equal?
            emit-j
            emit-jl
            emit-je
            emit-jnl
            emit-jne
            emit-jge
            emit-jnge
            emit-jtable

            emit-fixnum?
            emit-heap-object?
            emit-char?
            emit-undefined?
            emit-null?
            emit-false?
            emit-nil?

            emit-untag-fixnum
            emit-tag-fixnum
            emit-untag-char
            emit-tag-char

            emit-s64->f64

            emit-throw
            (emit-throw/value* . emit-throw/value)
            (emit-throw/value+data* . emit-throw/value+data)
            emit-unreachable

            emit-pair?
            emit-struct?
            emit-symbol?
            emit-variable?
            emit-vector?
            emit-mutable-vector?
            emit-immutable-vector?
            emit-weak-vector?
            emit-string?
            emit-heap-number?
            emit-hash-table?
            emit-pointer?
            emit-fluid?
            emit-stringbuf?
            emit-dynamic-state?
            emit-frame?
            emit-keyword?
            emit-syntax?
            emit-program?
            emit-vm-continuation?
            emit-bytevector?
            emit-weak-set?
            emit-weak-table?
            emit-array?
            emit-bitvector?
            emit-port?
            emit-smob?
            emit-bignum?
            emit-flonum?
            emit-compnum?
            emit-fracnum?

            emit-allocate-words
            emit-allocate-words/immediate
            emit-allocate-pointerless-words
            emit-allocate-pointerless-words/immediate

            emit-scm-ref
            emit-scm-set!
            emit-scm-ref/tag
            emit-scm-set!/tag
            emit-scm-ref/immediate
            emit-scm-set!/immediate

            emit-word-ref
            emit-word-set!
            emit-word-ref/immediate
            emit-word-set!/immediate

            emit-pointer-ref/immediate
            emit-pointer-set!/immediate
            emit-tail-pointer-ref/immediate

            emit-u8-ref
            emit-s8-ref
            emit-u16-ref
            emit-s16-ref
            emit-u32-ref
            emit-s32-ref
            emit-u64-ref
            emit-s64-ref
            emit-f32-ref
            emit-f64-ref
            emit-u8-set!
            emit-s8-set!
            emit-u16-set!
            emit-s16-set!
            emit-u32-set!
            emit-s32-set!
            emit-u64-set!
            emit-s64-set!
            emit-f32-set!
            emit-f64-set!

            emit-atomic-scm-ref/immediate
            emit-atomic-scm-set!/immediate
            emit-atomic-scm-swap!/immediate
            emit-atomic-scm-compare-and-swap!/immediate

            ;; Intrinsics.
            emit-add
            emit-add/immediate
            emit-sub
            emit-sub/immediate
            emit-mul
            emit-div
            emit-quo
            emit-rem
            emit-mod
            emit-inexact
            emit-abs
            emit-sqrt
            emit-floor
            emit-ceiling
            emit-sin
            emit-cos
            emit-tan
            emit-asin
            emit-acos
            emit-atan
            emit-atan2
            emit-fabs
            emit-fsqrt
            emit-ffloor
            emit-fceiling
            emit-fsin
            emit-fcos
            emit-ftan
            emit-fasin
            emit-facos
            emit-fatan
            emit-fatan2
            emit-logand
            emit-logior
            emit-logxor
            emit-logsub
            emit-string-set!
            emit-string->number
            emit-string->symbol
            emit-symbol->keyword
            emit-class-of
            emit-scm->f64
            emit-scm->u64
            emit-scm->u64/truncate
            emit-scm->s64
            emit-u64->scm
            emit-s64->scm
            emit-wind
            emit-unwind
            emit-push-fluid
            emit-pop-fluid
            emit-fluid-ref
            emit-fluid-set!
            emit-push-dynamic-state
            emit-pop-dynamic-state
            emit-lsh
            emit-rsh
            emit-lsh/immediate
            emit-rsh/immediate
            emit-resolve-module
            emit-module-variable
            emit-lookup
            emit-lookup-bound
            emit-lookup-bound-public
            emit-lookup-bound-private
            emit-define!
            emit-current-module
            emit-symbol->string
            emit-string-utf8-length
            emit-string->utf8
            emit-utf8->string

            ;; Intrinsics for use by the baseline compiler.
            emit-$car
            emit-$cdr
            emit-$set-car!
            emit-$set-cdr!
            emit-$variable-ref
            emit-$variable-set!
            emit-$vector-length
            emit-$vector-ref
            emit-$vector-set!
            emit-$vector-ref/immediate
            emit-$vector-set!/immediate
            emit-$allocate-struct
            emit-$struct-vtable
            emit-$struct-ref
            emit-$struct-set!
            emit-$struct-ref/immediate
            emit-$struct-set!/immediate

            emit-cache-ref
            emit-cache-set!

            emit-call
            emit-call-label
            emit-tail-call
            emit-tail-call-label
            (emit-instrument-entry* . emit-instrument-entry)
            (emit-instrument-loop* . emit-instrument-loop)
            emit-receive-values
            emit-return-values
            emit-shuffle-down
            emit-call/cc
            emit-abort
            emit-builtin-ref
            emit-assert-nargs-ee
            emit-assert-nargs-ge
            emit-assert-nargs-le
            emit-reset-frame
            emit-assert-nargs-ee/locals
            emit-bind-kwargs
            emit-bind-rest
            emit-load-label
            emit-resolve
            emit-prompt
            emit-current-thread
            emit-fadd
            emit-fsub
            emit-fmul
            emit-fdiv
            emit-uadd
            emit-usub
            emit-umul
            emit-uadd/immediate
            emit-usub/immediate
            emit-umul/immediate
            emit-ulogand
            emit-ulogand/immediate
            emit-ulogior
            emit-ulogxor
            emit-ulogsub
            emit-ursh
            emit-srsh
            emit-ulsh
            emit-ursh/immediate
            emit-srsh/immediate
            emit-ulsh/immediate
            emit-make-array
            emit-load-f64
            emit-load-u64
            emit-load-s64
            emit-handle-interrupts

            emit-text
            link-assembly))


