1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609 |
- @c -*-texinfo-*-
- @c This is part of the GNU Guile Reference Manual.
- @c Copyright (C) 2008,2009,2010,2011,2013,2015
- @c Free Software Foundation, Inc.
- @c See the file guile.texi for copying conditions.
- @node A Virtual Machine for Guile
- @section A Virtual Machine for Guile
- Guile has both an interpreter and a compiler. To a user, the difference
- is transparent---interpreted and compiled procedures can call each other
- as they please.
- The difference is that the compiler creates and interprets bytecode
- for a custom virtual machine, instead of interpreting the
- S-expressions directly. Loading and running compiled code is faster
- than loading and running source code.
- The virtual machine that does the bytecode interpretation is a part of
- Guile itself. This section describes the nature of Guile's virtual
- machine.
- @menu
- * Why a VM?::
- * VM Concepts::
- * Stack Layout::
- * Variables and the VM::
- * VM Programs::
- * Object File Format::
- * Instruction Set::
- @end menu
- @node Why a VM?
- @subsection Why a VM?
- @cindex interpreter
- For a long time, Guile only had an interpreter. Guile's interpreter
- operated directly on the S-expression representation of Scheme source
- code.
- But while the interpreter was highly optimized and hand-tuned, it still
- performed many needless computations during the course of evaluating an
- expression. For example, application of a function to arguments
- needlessly consed up the arguments in a list. Evaluation of an
- expression always had to figure out what the car of the expression is --
- a procedure, a memoized form, or something else. All values have to be
- allocated on the heap. Et cetera.
- The solution to this problem was to compile the higher-level language,
- Scheme, into a lower-level language for which all of the checks and
- dispatching have already been done---the code is instead stripped to
- the bare minimum needed to ``do the job''.
- The question becomes then, what low-level language to choose? There
- are many options. We could compile to native code directly, but that
- poses portability problems for Guile, as it is a highly cross-platform
- project.
- So we want the performance gains that compilation provides, but we
- also want to maintain the portability benefits of a single code path.
- The obvious solution is to compile to a virtual machine that is
- present on all Guile installations.
- The easiest (and most fun) way to depend on a virtual machine is to
- implement the virtual machine within Guile itself. This way the
- virtual machine provides what Scheme needs (tail calls, multiple
- values, @code{call/cc}) and can provide optimized inline instructions
- for Guile (@code{cons}, @code{struct-ref}, etc.).
- So this is what Guile does. The rest of this section describes that VM
- that Guile implements, and the compiled procedures that run on it.
- Before moving on, though, we should note that though we spoke of the
- interpreter in the past tense, Guile still has an interpreter. The
- difference is that before, it was Guile's main evaluator, and so was
- implemented in highly optimized C; now, it is actually implemented in
- Scheme, and compiled down to VM bytecode, just like any other program.
- (There is still a C interpreter around, used to bootstrap the compiler,
- but it is not normally used at runtime.)
- The upside of implementing the interpreter in Scheme is that we preserve
- tail calls and multiple-value handling between interpreted and compiled
- code. The downside is that the interpreter in Guile 2.2 is still about
- twice as slow as the interpreter in 1.8. Since Scheme users are mostly
- running compiled code, the compiler's speed more than makes up for the
- loss. In any case, once we have native compilation for Scheme code, we
- expect the self-hosted interpreter to handily beat the old hand-tuned C
- implementation.
- Also note that this decision to implement a bytecode compiler does not
- preclude native compilation. We can compile from bytecode to native
- code at runtime, or even do ahead of time compilation. More
- possibilities are discussed in @ref{Extending the Compiler}.
- @node VM Concepts
- @subsection VM Concepts
- Compiled code is run by a virtual machine (VM). Each thread has its own
- VM. The virtual machine executes the sequence of instructions in a
- procedure.
- Each VM instruction starts by indicating which operation it is, and then
- follows by encoding its source and destination operands. Each procedure
- declares that it has some number of local variables, including the
- function arguments. These local variables form the available operands
- of the procedure, and are accessed by index.
- The local variables for a procedure are stored on a stack. Calling a
- procedure typically enlarges the stack, and returning from a procedure
- shrinks it. Stack memory is exclusive to the virtual machine that owns
- it.
- In addition to their stacks, virtual machines also have access to the
- global memory (modules, global bindings, etc) that is shared among other
- parts of Guile, including other VMs.
- The registers that a VM has are as follows:
- @itemize
- @item ip - Instruction pointer
- @item sp - Stack pointer
- @item fp - Frame pointer
- @end itemize
- In other architectures, the instruction pointer is sometimes called the
- ``program counter'' (pc). This set of registers is pretty typical for
- virtual machines; their exact meanings in the context of Guile's VM are
- described in the next section.
- @node Stack Layout
- @subsection Stack Layout
- The stack of Guile's virtual machine is composed of @dfn{frames}. Each
- frame corresponds to the application of one compiled procedure, and
- contains storage space for arguments, local variables, and some
- bookkeeping information (such as what to do after the frame is
- finished).
- While the compiler is free to do whatever it wants to, as long as the
- semantics of a computation are preserved, in practice every time you
- call a function, a new frame is created. (The notable exception of
- course is the tail call case, @pxref{Tail Calls}.)
- The structure of the top stack frame is as follows:
- @example
- | ... |
- +==================+ <- fp + 2 = SCM_FRAME_PREVIOUS_SP (fp)
- | Dynamic link |
- +------------------+
- | Return address |
- +==================+ <- fp
- | Local 0 |
- +------------------+
- | Local 1 |
- +------------------+
- | ... |
- +------------------+
- | Local N-1 |
- \------------------/ <- sp
- @end example
- In the above drawing, the stack grows downward. At the beginning of a
- function call, the procedure being applied is in local 0, followed by
- the arguments from local 1. After the procedure checks that it is being
- passed a compatible set of arguments, the procedure allocates some
- additional space in the frame to hold variables local to the function.
- Note that once a value in a local variable slot is no longer needed,
- Guile is free to re-use that slot. This applies to the slots that were
- initially used for the callee and arguments, too. For this reason,
- backtraces in Guile aren't always able to show all of the arguments: it
- could be that the slot corresponding to that argument was re-used by
- some other variable.
- The @dfn{return address} is the @code{ip} that was in effect before this
- program was applied. When we return from this activation frame, we will
- jump back to this @code{ip}. Likewise, the @dfn{dynamic link} is the
- offset of the @code{fp} that was in effect before this program was
- applied, relative to the current @code{fp}.
- To prepare for a non-tail application, Guile's VM will emit code that
- shuffles the function to apply and its arguments into appropriate stack
- slots, with two free slots below them. The call then initializes those
- free slots with the current @code{ip} and @code{fp}, and updates
- @code{ip} to point to the function entry, and @code{fp} to point to the
- new call frame.
- In this way, the dynamic link links the current frame to the previous
- frame. Computing a stack trace involves traversing these frames.
- Each stack local in Guile is 64 bits wide, even on 32-bit architectures.
- This allows Guile to preserve its uniform treatment of stack locals
- while allowing for unboxed arithmetic on 64-bit integers and
- floating-point numbers. @xref{Instruction Set}, for more on unboxed
- arithmetic.
- As an implementation detail, we actually store the dynamic link as an
- offset and not an absolute value because the stack can move at runtime
- as it expands or during partial continuation calls. If it were an
- absolute value, we would have to walk the frames, relocating frame
- pointers.
- @node Variables and the VM
- @subsection Variables and the VM
- Consider the following Scheme code as an example:
- @example
- (define (foo a)
- (lambda (b) (list foo a b)))
- @end example
- Within the lambda expression, @code{foo} is a top-level variable,
- @code{a} is a lexically captured variable, and @code{b} is a local
- variable.
- Another way to refer to @code{a} and @code{b} is to say that @code{a} is
- a ``free'' variable, since it is not defined within the lambda, and
- @code{b} is a ``bound'' variable. These are the terms used in the
- @dfn{lambda calculus}, a mathematical notation for describing functions.
- The lambda calculus is useful because it is a language in which to
- reason precisely about functions and variables. It is especially good
- at describing scope relations, and it is for that reason that we mention
- it here.
- Guile allocates all variables on the stack. When a lexically enclosed
- procedure with free variables---a @dfn{closure}---is created, it copies
- those variables into its free variable vector. References to free
- variables are then redirected through the free variable vector.
- If a variable is ever @code{set!}, however, it will need to be
- heap-allocated instead of stack-allocated, so that different closures
- that capture the same variable can see the same value. Also, this
- allows continuations to capture a reference to the variable, instead
- of to its value at one point in time. For these reasons, @code{set!}
- variables are allocated in ``boxes''---actually, in variable cells.
- @xref{Variables}, for more information. References to @code{set!}
- variables are indirected through the boxes.
- Thus perhaps counterintuitively, what would seem ``closer to the
- metal'', viz @code{set!}, actually forces an extra memory allocation and
- indirection. Sometimes Guile's optimizer can remove this allocation,
- but not always.
- Going back to our example, @code{b} may be allocated on the stack, as
- it is never mutated.
- @code{a} may also be allocated on the stack, as it too is never
- mutated. Within the enclosed lambda, its value will be copied into
- (and referenced from) the free variables vector.
- @code{foo} is a top-level variable, because @code{foo} is not
- lexically bound in this example.
- @node VM Programs
- @subsection Compiled Procedures are VM Programs
- By default, when you enter in expressions at Guile's REPL, they are
- first compiled to bytecode. Then that bytecode is executed to produce a
- value. If the expression evaluates to a procedure, the result of this
- process is a compiled procedure.
- A compiled procedure is a compound object consisting of its bytecode and
- a reference to any captured lexical variables. In addition, when a
- procedure is compiled, it has associated metadata written to side
- tables, for instance a line number mapping, or its docstring. You can
- pick apart these pieces with the accessors in @code{(system vm
- program)}. @xref{Compiled Procedures}, for a full API reference.
- A procedure may reference data that was statically allocated when the
- procedure was compiled. For example, a pair of immediate objects
- (@pxref{Immediate objects}) can be allocated directly in the memory
- segment that contains the compiled bytecode, and accessed directly by
- the bytecode.
- Another use for statically allocated data is to serve as a cache for a
- bytecode. Top-level variable lookups are handled in this way. If the
- @code{toplevel-box} instruction finds that it does not have a cached
- variable for a top-level reference, it accesses other static data to
- resolve the reference, and fills in the cache slot. Thereafter all
- access to the variable goes through the cache cell. The variable's
- value may change in the future, but the variable itself will not.
- We can see how these concepts tie together by disassembling the
- @code{foo} function we defined earlier to see what is going on:
- @smallexample
- scheme@@(guile-user)> (define (foo a) (lambda (b) (list foo a b)))
- scheme@@(guile-user)> ,x foo
- Disassembly of #<procedure foo (a)> at #xea4ce4:
- 0 (assert-nargs-ee/locals 2 0) ;; 2 slots (1 arg) at (unknown file):1:0
- 1 (make-closure 1 7 1) ;; anonymous procedure at #xea4d04 (1 free var)
- 4 (free-set! 1 0 0) ;; free var 0
- 6 (mov 0 1)
- 7 (return-values 2) ;; 1 value
- ----------------------------------------
- Disassembly of anonymous procedure at #xea4d04:
- 0 (assert-nargs-ee/locals 2 2) ;; 4 slots (1 arg) at (unknown file):1:16
- 1 (toplevel-box 1 74 58 68 #t) ;; `foo'
- 6 (box-ref 1 1)
- 7 (make-short-immediate 0 772) ;; () at (unknown file):1:28
- 8 (cons 2 2 0)
- 9 (free-ref 3 3 0) ;; free var 0
- 11 (cons 3 3 2)
- 12 (cons 2 1 3)
- 13 (return-values 2) ;; 1 value
- @end smallexample
- First there's some prelude, where @code{foo} checks that it was called
- with only 1 argument. Then at @code{ip} 1, we allocate a new closure
- and store it in slot 1, relative to the @code{sp}.
- At run-time, local variables in Guile are usually addressed relative to
- the stack pointer, which leads to a pleasantly efficient
- @code{sp[@var{n}]} access. However it can make the disassembly hard to
- read, because the @code{sp} can change during the function, and because
- incoming arguments are relative to the @code{fp}, not the @code{sp}.
- To know what @code{fp}-relative slot corresponds to an
- @code{sp}-relative reference, scan up in the disassembly until you get
- to a ``@var{n} slots'' annotation; in our case, 2, indicating that the
- frame has space for 2 slots. Thus a zero-indexed @code{sp}-relative
- slot of 1 corresponds to the @code{fp}-relative slot of 0, which
- initially held the value of the closure being called. This means that
- Guile doesn't need the value of the closure to compute its result, and
- so slot 0 was free for re-use, in this case for the result of making a
- new closure.
- A closure is code with data. The @code{6} in the @code{(make-closure 1
- 6 1)} is a relative offset from the instruction pointer of the code for
- the closure, and the final @code{1} indicates that the closure has space
- for 1 free variable. @code{Ip} 4 initializes free variable 0 in the new
- closure with the value from @code{sp}-relative slot 0, which corresponds
- to @code{fp}-relative slot 1, the first argument of @code{foo}:
- @code{a}. Finally we return the closure.
- The second stanza disassembles the code for the closure. After the
- prelude, we load the variable for the toplevel variable @code{foo} into
- slot 1. This lookup occurs lazily, the first time the variable is
- actually referenced, and the location of the lookup is cached so that
- future references are very cheap. @xref{Top-Level Environment
- Instructions}, for more details. The @code{box-ref} dereferences the
- variable cell, replacing the contents of slot 1.
- What follows is a sequence of conses to build up the result list.
- @code{Ip} 7 makes the tail of the list. @code{Ip} 8 conses on the value
- in slot 2, corresponding to the first argument to the closure: @code{b}.
- @code{Ip} 9 loads free variable 0 of slot 3 -- the procedure being
- called, in @code{fp}-relative slot 0 -- into slot 3, then @code{ip} 11
- conses it onto the list. Finally we cons the value in slot 1,
- containing the @code{foo} toplevel, onto the front of the list, and we
- return it.
- @node Object File Format
- @subsection Object File Format
- To compile a file to disk, we need a format in which to write the
- compiled code to disk, and later load it into Guile. A good @dfn{object
- file format} has a number of characteristics:
- @itemize
- @item Above all else, it should be very cheap to load a compiled file.
- @item It should be possible to statically allocate constants in the
- file. For example, a bytevector literal in source code can be emitted
- directly into the object file.
- @item The compiled file should enable maximum code and data sharing
- between different processes.
- @item The compiled file should contain debugging information, such as
- line numbers, but that information should be separated from the code
- itself. It should be possible to strip debugging information if space
- is tight.
- @end itemize
- These characteristics are not specific to Scheme. Indeed, mainstream
- languages like C and C++ have solved this issue many times in the past.
- Guile builds on their work by adopting ELF, the object file format of
- GNU and other Unix-like systems, as its object file format. Although
- Guile uses ELF on all platforms, we do not use platform support for ELF.
- Guile implements its own linker and loader. The advantage of using ELF
- is not sharing code, but sharing ideas. ELF is simply a well-designed
- object file format.
- An ELF file has two meta-tables describing its contents. The first
- meta-table is for the loader, and is called the @dfn{program table} or
- sometimes the @dfn{segment table}. The program table divides the file
- into big chunks that should be treated differently by the loader.
- Mostly the difference between these @dfn{segments} is their
- permissions.
- Typically all segments of an ELF file are marked as read-only, except
- that part that represents modifiable static data or static data that
- needs load-time initialization. Loading an ELF file is as simple as
- mmapping the thing into memory with read-only permissions, then using
- the segment table to mark a small sub-region of the file as writable.
- This writable section is typically added to the root set of the garbage
- collector as well.
- One ELF segment is marked as ``dynamic'', meaning that it has data of
- interest to the loader. Guile uses this segment to record the Guile
- version corresponding to this file. There is also an entry in the
- dynamic segment that points to the address of an initialization thunk
- that is run to perform any needed link-time initialization. (This is
- like dynamic relocations for normal ELF shared objects, except that we
- compile the relocations as a procedure instead of having the loader
- interpret a table of relocations.) Finally, the dynamic segment marks
- the location of the ``entry thunk'' of the object file. This thunk is
- returned to the caller of @code{load-thunk-from-memory} or
- @code{load-thunk-from-file}. When called, it will execute the ``body''
- of the compiled expression.
- The other meta-table in an ELF file is the @dfn{section table}. Whereas
- the program table divides an ELF file into big chunks for the loader,
- the section table specifies small sections for use by introspective
- tools like debuggers or the like. One segment (program table entry)
- typically contains many sections. There may be sections outside of any
- segment, as well.
- Typical sections in a Guile @code{.go} file include:
- @table @code
- @item .rtl-text
- Bytecode.
- @item .data
- Data that needs initialization, or which may be modified at runtime.
- @item .rodata
- Statically allocated data that needs no run-time initialization, and
- which therefore can be shared between processes.
- @item .dynamic
- The dynamic section, discussed above.
- @item .symtab
- @itemx .strtab
- A table mapping addresses in the @code{.rtl-text} to procedure names.
- @code{.strtab} is used by @code{.symtab}.
- @item .guile.procprops
- @itemx .guile.arities
- @itemx .guile.arities.strtab
- @itemx .guile.docstrs
- @itemx .guile.docstrs.strtab
- Side tables of procedure properties, arities, and docstrings.
- @item .guile.docstrs.strtab
- Side table of frame maps, describing the set of live slots for ever
- return point in the program text, and whether those slots are pointers
- are not. Used by the garbage collector.
- @item .debug_info
- @itemx .debug_abbrev
- @itemx .debug_str
- @itemx .debug_loc
- @itemx .debug_line
- Debugging information, in DWARF format. See the DWARF specification,
- for more information.
- @item .shstrtab
- Section name string table.
- @end table
- For more information, see @uref{http://linux.die.net/man/5/elf,,the
- elf(5) man page}. See @uref{http://dwarfstd.org/,the DWARF
- specification} for more on the DWARF debugging format. Or if you are an
- adventurous explorer, try running @code{readelf} or @code{objdump} on
- compiled @code{.go} files. It's good times!
- @node Instruction Set
- @subsection Instruction Set
- There are currently about 175 instructions in Guile's virtual machine.
- These instructions represent atomic units of a program's execution.
- Ideally, they perform one task without conditional branches, then
- dispatch to the next instruction in the stream.
- Instructions themselves are composed of 1 or more 32-bit units. The low
- 8 bits of the first word indicate the opcode, and the rest of
- instruction describe the operands. There are a number of different ways
- operands can be encoded.
- @table @code
- @item s@var{n}
- An unsigned @var{n}-bit integer, indicating the @code{sp}-relative index
- of a local variable.
- @item f@var{n}
- An unsigned @var{n}-bit integer, indicating the @code{fp}-relative index
- of a local variable. Used when a continuation accepts a variable number
- of values, to shuffle received values into known locations in the
- frame.
- @item c@var{n}
- An unsigned @var{n}-bit integer, indicating a constant value.
- @item l24
- An offset from the current @code{ip}, in 32-bit units, as a signed
- 24-bit value. Indicates a bytecode address, for a relative jump.
- @item i16
- @itemx i32
- An immediate Scheme value (@pxref{Immediate objects}), encoded directly
- in 16 or 32 bits.
- @item a32
- @itemx b32
- An immediate Scheme value, encoded as a pair of 32-bit words.
- @code{a32} and @code{b32} values always go together on the same opcode,
- and indicate the high and low bits, respectively. Normally only used on
- 64-bit systems.
- @item n32
- A statically allocated non-immediate. The address of the non-immediate
- is encoded as a signed 32-bit integer, and indicates a relative offset
- in 32-bit units. Think of it as @code{SCM x = ip + offset}.
- @item r32
- Indirect scheme value, like @code{n32} but indirected. Think of it as
- @code{SCM *x = ip + offset}.
- @item l32
- @item lo32
- An ip-relative address, as a signed 32-bit integer. Could indicate a
- bytecode address, as in @code{make-closure}, or a non-immediate address,
- as with @code{static-patch!}.
- @code{l32} and @code{lo32} are the same from the perspective of the
- virtual machine. The difference is that an assembler might want to
- allow an @code{lo32} address to be specified as a label and then some
- number of words offset from that label, for example when patching a
- field of a statically allocated object.
- @item b1
- A boolean value: 1 for true, otherwise 0.
- @item x@var{n}
- An ignored sequence of @var{n} bits.
- @end table
- An instruction is specified by giving its name, then describing its
- operands. The operands are packed by 32-bit words, with earlier
- operands occupying the lower bits.
- For example, consider the following instruction specification:
- @deftypefn Instruction {} free-set! s12:@var{dst} s12:@var{src} x8:@var{_} c24:@var{idx}
- Set free variable @var{idx} from the closure @var{dst} to @var{src}.
- @end deftypefn
- The first word in the instruction will start with the 8-bit value
- corresponding to the @var{free-set!} opcode in the low bits, followed by
- @var{dst} and @var{src} as 12-bit values. The second word starts with 8
- dead bits, followed by the index as a 24-bit immediate value.
- Sometimes the compiler can figure out that it is compiling a special
- case that can be run more efficiently. So, for example, while Guile
- offers a generic test-and-branch instruction, it also offers specific
- instructions for special cases, so that the following cases all have
- their own test-and-branch instructions:
- @example
- (if pred then else)
- (if (not pred) then else)
- (if (null? l) then else)
- (if (not (null? l)) then else)
- @end example
- In addition, some Scheme primitives have their own inline
- implementations. For example, in the previous section we saw
- @code{cons}.
- Finally, for instructions with operands that encode references to the
- stack, the interpretation of those stack values is up to the instruction
- itself. Most instructions expect their operands to be tagged SCM values
- (@code{scm} representation), but some instructions expect unboxed
- integers (@code{u64} and @code{s64} representations) or floating-point
- numbers (@var{f64} representation). Instructions have static types:
- they must receive their operands in the format they expect. It's up to
- the compiler to ensure this is the case. Unless otherwise mentioned,
- all operands and results are boxed as SCM values.
- @menu
- * Lexical Environment Instructions::
- * Top-Level Environment Instructions::
- * Procedure Call and Return Instructions::
- * Function Prologue Instructions::
- * Trampoline Instructions::
- * Branch Instructions::
- * Constant Instructions::
- * Dynamic Environment Instructions::
- * Miscellaneous Instructions::
- * Inlined Scheme Instructions::
- * Inlined Mathematical Instructions::
- * Inlined Bytevector Instructions::
- * Unboxed Integer Arithmetic::
- * Unboxed Floating-Point Arithmetic::
- @end menu
- @node Lexical Environment Instructions
- @subsubsection Lexical Environment Instructions
- These instructions access and mutate the lexical environment of a
- compiled procedure---its free and bound variables. @xref{Stack Layout},
- for more information on the format of stack frames.
- @deftypefn Instruction {} mov s12:@var{dst} s12:@var{src}
- @deftypefnx Instruction {} long-mov s24:@var{dst} x8:@var{_} s24:@var{src}
- Copy a value from one local slot to another.
- As discussed previously, procedure arguments and local variables are
- allocated to local slots. Guile's compiler tries to avoid shuffling
- variables around to different slots, which often makes @code{mov}
- instructions redundant. However there are some cases in which shuffling
- is necessary, and in those cases, @code{mov} is the thing to use.
- @end deftypefn
- @deftypefn Instruction {} long-fmov f24:@var{dst} x8:@var{_} f24:@var{src}
- Copy a value from one local slot to another, but addressing slots
- relative to the @code{fp} instead of the @code{sp}. This is used when
- shuffling values into place after multiple-value returns.
- @end deftypefn
- @deftypefn Instruction {} make-closure s24:@var{dst} l32:@var{offset} x8:@var{_} c24:@var{nfree}
- Make a new closure, and write it to @var{dst}. The code for the closure
- will be found at @var{offset} words from the current @code{ip}.
- @var{offset} is a signed 32-bit integer. Space for @var{nfree} free
- variables will be allocated.
- The size of a closure is currently two words, plus one word per free
- variable.
- @end deftypefn
- @deftypefn Instruction {} free-ref s12:@var{dst} s12:@var{src} x8:@var{_} c24:@var{idx}
- Load free variable @var{idx} from the closure @var{src} into local slot
- @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} free-set! s12:@var{dst} s12:@var{src} x8:@var{_} c24:@var{idx}
- Set free variable @var{idx} from the closure @var{dst} to @var{src}.
- This instruction is usually used when initializing a closure's free
- variables, but not to mutate free variables, as variables that are
- assigned are boxed.
- @end deftypefn
- Recall that variables that are assigned are usually allocated in boxes,
- so that continuations and closures can capture their identity and not
- their value at one point in time. Variables are also used in the
- implementation of top-level bindings; see the next section for more
- information.
- @deftypefn Instruction {} box s12:@var{dst} s12:@var{src}
- Create a new variable holding @var{src}, and place it in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} box-ref s12:@var{dst} s12:@var{src}
- Unpack the variable at @var{src} into @var{dst}, asserting that the
- variable is actually bound.
- @end deftypefn
- @deftypefn Instruction {} box-set! s12:@var{dst} s12:@var{src}
- Set the contents of the variable at @var{dst} to @var{set}.
- @end deftypefn
- @node Top-Level Environment Instructions
- @subsubsection Top-Level Environment Instructions
- These instructions access values in the top-level environment: bindings
- that were not lexically apparent at the time that the code in question
- was compiled.
- The location in which a toplevel binding is stored can be looked up once
- and cached for later. The binding itself may change over time, but its
- location will stay constant.
- @deftypefn Instruction {} current-module s24:@var{dst}
- Store the current module in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} resolve s24:@var{dst} b1:@var{bound?} x7:@var{_} s24:@var{sym}
- Resolve @var{sym} in the current module, and place the resulting
- variable in @var{dst}. An error will be signalled if no variable is
- found. If @var{bound?} is true, an error will be signalled if the
- variable is unbound.
- @end deftypefn
- @deftypefn Instruction {} define! s12:@var{sym} s12:@var{val}
- Look up a binding for @var{sym} in the current module, creating it if
- necessary. Set its value to @var{val}.
- @end deftypefn
- @deftypefn Instruction {} toplevel-box s24:@var{dst} r32:@var{var-offset} r32:@var{mod-offset} n32:@var{sym-offset} b1:@var{bound?} x31:@var{_}
- Load a value. The value will be fetched from memory, @var{var-offset}
- 32-bit words away from the current instruction pointer.
- @var{var-offset} is a signed value. Up to here, @code{toplevel-box} is
- like @code{static-ref}.
- Then, if the loaded value is a variable, it is placed in @var{dst}, and
- control flow continues.
- Otherwise, we have to resolve the variable. In that case we load the
- module from @var{mod-offset}, just as we loaded the variable. Usually
- the module gets set when the closure is created. @var{sym-offset}
- specifies the name, as an offset to a symbol.
- We use the module and the symbol to resolve the variable, placing it in
- @var{dst}, and caching the resolved variable so that we will hit the
- cache next time. If @var{bound?} is true, an error will be signalled if
- the variable is unbound.
- @end deftypefn
- @deftypefn Instruction {} module-box s24:@var{dst} r32:@var{var-offset} n32:@var{mod-offset} n32:@var{sym-offset} b1:@var{bound?} x31:@var{_}
- Like @code{toplevel-box}, except @var{mod-offset} points at a module
- identifier instead of the module itself. A module identifier is a
- module name, as a list, prefixed by a boolean. If the prefix is true,
- then the variable is resolved relative to the module's public interface
- instead of its private interface.
- @end deftypefn
- @node Procedure Call and Return Instructions
- @subsubsection Procedure Call and Return Instructions
- As described earlier (@pxref{Stack Layout}), Guile's calling convention
- is that arguments are passed and values returned on the stack.
- For calls, both in tail position and in non-tail position, we require
- that the procedure and the arguments already be shuffled into place
- befor the call instruction. ``Into place'' for a tail call means that
- the procedure should be in slot 0, relative to the @code{fp}, and the
- arguments should follow. For a non-tail call, if the procedure is in
- @code{fp}-relative slot @var{n}, the arguments should follow from slot
- @var{n}+1, and there should be two free slots at @var{n}-1 and @var{n}-2
- in which to save the @code{ip} and @code{fp}.
- Returning values is similar. Multiple-value returns should have values
- already shuffled down to start from @code{fp}-relative slot 1 before
- emitting @code{return-values}. We start from slot 1 instead of slot 0
- to make tail calls to @code{values} trivial.
- In both calls and returns, the @code{sp} is used to indicate to the
- callee or caller the number of arguments or return values, respectively.
- After receiving return values, it is the caller's responsibility to
- @dfn{restore the frame} by resetting the @code{sp} to its former value.
- @deftypefn Instruction {} call f24:@var{proc} x8:@var{_} c24:@var{nlocals}
- Call a procedure. @var{proc} is the local corresponding to a procedure.
- The two values below @var{proc} will be overwritten by the saved call
- frame data. The new frame will have space for @var{nlocals} locals: one
- for the procedure, and the rest for the arguments which should already
- have been pushed on.
- When the call returns, execution proceeds with the next instruction.
- There may be any number of values on the return stack; the precise
- number can be had by subtracting the address of @var{proc} from the
- post-call @code{sp}.
- @end deftypefn
- @deftypefn Instruction {} call-label f24:@var{proc} x8:@var{_} c24:@var{nlocals} l32:@var{label}
- Call a procedure in the same compilation unit.
- This instruction is just like @code{call}, except that instead of
- dereferencing @var{proc} to find the call target, the call target is
- known to be at @var{label}, a signed 32-bit offset in 32-bit units from
- the current @code{ip}. Since @var{proc} is not dereferenced, it may be
- some other representation of the closure.
- @end deftypefn
- @deftypefn Instruction {} tail-call c24:@var{nlocals}
- Tail-call a procedure. Requires that the procedure and all of the
- arguments have already been shuffled into position. Will reset the
- frame to @var{nlocals}.
- @end deftypefn
- @deftypefn Instruction {} tail-call-label c24:@var{nlocals} l32:@var{label}
- Tail-call a known procedure. As @code{call} is to @code{call-label},
- @code{tail-call} is to @code{tail-call-label}.
- @end deftypefn
- @deftypefn Instruction {} tail-call/shuffle f24:@var{from}
- Tail-call a procedure. The procedure should already be set to slot 0.
- The rest of the args are taken from the frame, starting at @var{from},
- shuffled down to start at slot 0. This is part of the implementation of
- the @code{call-with-values} builtin.
- @end deftypefn
- @deftypefn Instruction {} receive f12:@var{dst} f12:@var{proc} x8:@var{_} c24:@var{nlocals}
- Receive a single return value from a call whose procedure was in
- @var{proc}, asserting that the call actually returned at least one
- value. Afterwards, resets the frame to @var{nlocals} locals.
- @end deftypefn
- @deftypefn Instruction {} receive-values f24:@var{proc} b1:@var{allow-extra?} x7:@var{_} c24:@var{nvalues}
- Receive a return of multiple values from a call whose procedure was in
- @var{proc}. If fewer than @var{nvalues} values were returned, signal an
- error. Unless @var{allow-extra?} is true, require that the number of
- return values equals @var{nvalues} exactly. After @code{receive-values}
- has run, the values can be copied down via @code{mov}, or used in place.
- @end deftypefn
- @deftypefn Instruction {} return-values c24:@var{nlocals}
- Return a number of values from a call frame. This opcode corresponds to
- an application of @code{values} in tail position. As with tail calls,
- we expect that the values have already been shuffled down to a
- contiguous array starting at slot 1. If @var{nlocals} is nonzero, reset
- the frame to hold that number of locals. Note that a frame reset to 1
- local returns 0 values.
- @end deftypefn
- @deftypefn Instruction {} call/cc x24:@var{_}
- Capture the current continuation, and tail-apply the procedure in local
- slot 1 to it. This instruction is part of the implementation of
- @code{call/cc}, and is not generated by the compiler.
- @end deftypefn
- @node Function Prologue Instructions
- @subsubsection Function Prologue Instructions
- A function call in Guile is very cheap: the VM simply hands control to
- the procedure. The procedure itself is responsible for asserting that it
- has been passed an appropriate number of arguments. This strategy allows
- arbitrarily complex argument parsing idioms to be developed, without
- harming the common case.
- For example, only calls to keyword-argument procedures ``pay'' for the
- cost of parsing keyword arguments. (At the time of this writing, calling
- procedures with keyword arguments is typically two to four times as
- costly as calling procedures with a fixed set of arguments.)
- @deftypefn Instruction {} assert-nargs-ee c24:@var{expected}
- @deftypefnx Instruction {} assert-nargs-ge c24:@var{expected}
- @deftypefnx Instruction {} assert-nargs-le c24:@var{expected}
- If the number of actual arguments is not @code{==}, @code{>=}, or
- @code{<=} @var{expected}, respectively, signal an error.
- The number of arguments is determined by subtracting the stack pointer
- from the frame pointer (@code{fp - sp}). @xref{Stack Layout}, for more
- details on stack frames. Note that @var{expected} includes the
- procedure itself.
- @end deftypefn
- @deftypefn Instruction {} br-if-nargs-ne c24:@var{expected} x8:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-nargs-lt c24:@var{expected} x8:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-nargs-gt c24:@var{expected} x8:@var{_} l24:@var{offset}
- If the number of actual arguments is not equal, less than, or greater
- than @var{expected}, respectively, add @var{offset}, a signed 24-bit
- number, to the current instruction pointer. Note that @var{expected}
- includes the procedure itself.
- These instructions are used to implement multiple arities, as in
- @code{case-lambda}. @xref{Case-lambda}, for more information.
- @end deftypefn
- @deftypefn Instruction {} alloc-frame c24:@var{nlocals}
- Ensure that there is space on the stack for @var{nlocals} local
- variables, setting them all to @code{SCM_UNDEFINED}, except those values
- that are already on the stack.
- @end deftypefn
- @deftypefn Instruction {} reset-frame c24:@var{nlocals}
- Like @code{alloc-frame}, but doesn't check that the stack is big enough,
- and doesn't initialize values to @code{SCM_UNDEFINED}. Used to reset
- the frame size to something less than the size that was previously set
- via alloc-frame.
- @end deftypefn
- @deftypefn Instruction {} assert-nargs-ee/locals c12:@var{expected} c12:@var{nlocals}
- Equivalent to a sequence of @code{assert-nargs-ee} and
- @code{reserve-locals}. The number of locals reserved is @var{expected}
- + @var{nlocals}.
- @end deftypefn
- @deftypefn Instruction {} br-if-npos-gt c24:@var{nreq} x8:@var{_} c24:@var{npos} x8:@var{_} l24:@var{offset}
- Find the first positional argument after @var{nreq}. If it is greater
- than @var{npos}, jump to @var{offset}.
- This instruction is only emitted for functions with multiple clauses,
- and an earlier clause has keywords and no rest arguments.
- @xref{Case-lambda}, for more on how @code{case-lambda} chooses the
- clause to apply.
- @end deftypefn
- @deftypefn Instruction {} bind-kwargs c24:@var{nreq} c8:@var{flags} c24:@var{nreq-and-opt} x8:@var{_} c24:@var{ntotal} n32:@var{kw-offset}
- @var{flags} is a bitfield, whose lowest bit is @var{allow-other-keys},
- second bit is @var{has-rest}, and whose following six bits are unused.
- Find the last positional argument, and shuffle all the rest above
- @var{ntotal}. Initialize the intervening locals to
- @code{SCM_UNDEFINED}. Then load the constant at @var{kw-offset} words
- from the current @var{ip}, and use it and the @var{allow-other-keys}
- flag to bind keyword arguments. If @var{has-rest}, collect all shuffled
- arguments into a list, and store it in @var{nreq-and-opt}. Finally,
- clear the arguments that we shuffled up.
- The parsing is driven by a keyword arguments association list, looked up
- using @var{kw-offset}. The alist is a list of pairs of the form
- @code{(@var{kw} . @var{index})}, mapping keyword arguments to their
- local slot indices. Unless @code{allow-other-keys} is set, the parser
- will signal an error if an unknown key is found.
- A macro-mega-instruction.
- @end deftypefn
- @deftypefn Instruction {} bind-rest f24:@var{dst}
- Collect any arguments at or above @var{dst} into a list, and store that
- list at @var{dst}.
- @end deftypefn
- @node Trampoline Instructions
- @subsubsection Trampoline Instructions
- Though most applicable objects in Guile are procedures implemented in
- bytecode, not all are. There are primitives, continuations, and other
- procedure-like objects that have their own calling convention. Instead
- of adding special cases to the @code{call} instruction, Guile wraps
- these other applicable objects in VM trampoline procedures, then
- provides special support for these objects in bytecode.
- Trampoline procedures are typically generated by Guile at runtime, for
- example in response to a call to @code{scm_c_make_gsubr}. As such, a
- compiler probably shouldn't emit code with these instructions. However,
- it's still interesting to know how these things work, so we document
- these trampoline instructions here.
- @deftypefn Instruction {} subr-call x24:@var{_}
- Call a subr, passing all locals in this frame as arguments. Return from
- the calling frame.
- @end deftypefn
- @deftypefn Instruction {} foreign-call c12:@var{cif-idx} c12:@var{ptr-idx}
- Call a foreign function. Fetch the @var{cif} and foreign pointer from
- @var{cif-idx} and @var{ptr-idx}, both free variables. Return from the calling
- frame. Arguments are taken from the stack.
- @end deftypefn
- @deftypefn Instruction {} continuation-call c24:@var{contregs}
- Return to a continuation, nonlocally. The arguments to the continuation
- are taken from the stack. @var{contregs} is a free variable containing
- the reified continuation.
- @end deftypefn
- @deftypefn Instruction {} compose-continuation c24:@var{cont}
- Compose a partial continution with the current continuation. The
- arguments to the continuation are taken from the stack. @var{cont} is a
- free variable containing the reified continuation.
- @end deftypefn
- @deftypefn Instruction {} tail-apply x24:@var{_}
- Tail-apply the procedure in local slot 0 to the rest of the arguments.
- This instruction is part of the implementation of @code{apply}, and is
- not generated by the compiler.
- @end deftypefn
- @deftypefn Instruction {} builtin-ref s12:@var{dst} c12:@var{idx}
- Load a builtin stub by index into @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} apply-non-program x24:@var{_}
- An instruction used only by a special trampoline that the VM uses to
- apply non-programs. Using that trampoline allows profilers and
- backtrace utilities to avoid seeing the instruction pointer from the
- calling frame.
- @end deftypefn
- @node Branch Instructions
- @subsubsection Branch Instructions
- All offsets to branch instructions are 24-bit signed numbers, which
- count 32-bit units. This gives Guile effectively a 26-bit address range
- for relative jumps.
- @deftypefn Instruction {} br l24:@var{offset}
- Add @var{offset} to the current instruction pointer.
- @end deftypefn
- All the conditional branch instructions described below have an
- @var{invert} parameter, which if true reverses the test:
- @code{br-if-true} becomes @code{br-if-false}, and so on.
- @deftypefn Instruction {} br-if-true s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is true for the purposes of Scheme, add
- @var{offset} to the current instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-null s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is the end-of-list or Lisp nil, add
- @var{offset} to the current instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-nil s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is false to Lisp, add @var{offset} to the
- current instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-pair s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is a pair, add @var{offset} to the current
- instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-struct s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is a struct, add @var{offset} number to the
- current instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-char s24:@var{test} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{test} is a char, add @var{offset} to the current
- instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-tc7 s24:@var{test} b1:@var{invert} u7:@var{tc7} l24:@var{offset}
- If the value in @var{test} has the TC7 given in the second word, add
- @var{offset} to the current instruction pointer. TC7 codes are part of
- the way Guile represents non-immediate objects, and are deep wizardry.
- See @code{libguile/tags.h} for all the details.
- @end deftypefn
- @deftypefn Instruction {} br-if-eq s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-eqv s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{a} is @code{eq?} or @code{eqv?} to the value in
- @var{b}, respectively, add @var{offset} to the current instruction
- pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-= s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-< s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-<= s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the value in @var{a} is @code{=}, @code{<}, or @code{<=} to the value
- in @var{b}, respectively, add @var{offset} to the current instruction
- pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-logtest s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the bitwise intersection of the integers in @var{a} and @var{b} is
- nonzero, add @var{offset} to the current instruction pointer.
- @end deftypefn
- @node Constant Instructions
- @subsubsection Constant Instructions
- The following instructions load literal data into a program. There are
- two kinds.
- The first set of instructions loads immediate values. These
- instructions encode the immediate directly into the instruction stream.
- @deftypefn Instruction {} make-short-immediate s8:@var{dst} i16:@var{low-bits}
- Make an immediate whose low bits are @var{low-bits}, and whose top bits are
- 0.
- @end deftypefn
- @deftypefn Instruction {} make-long-immediate s24:@var{dst} i32:@var{low-bits}
- Make an immediate whose low bits are @var{low-bits}, and whose top bits are
- 0.
- @end deftypefn
- @deftypefn Instruction {} make-long-long-immediate s24:@var{dst} a32:@var{high-bits} b32:@var{low-bits}
- Make an immediate with @var{high-bits} and @var{low-bits}.
- @end deftypefn
- Non-immediate constant literals are referenced either directly or
- indirectly. For example, Guile knows at compile-time what the layout of
- a string will be like, and arranges to embed that object directly in the
- compiled image. A reference to a string will use
- @code{make-non-immediate} to treat a pointer into the compilation unit
- as a @code{SCM} value directly.
- @deftypefn Instruction {} make-non-immediate s24:@var{dst} n32:@var{offset}
- Load a pointer to statically allocated memory into @var{dst}. The
- object's memory is will be found @var{offset} 32-bit words away from the
- current instruction pointer. Whether the object is mutable or immutable
- depends on where it was allocated by the compiler, and loaded by the
- loader.
- @end deftypefn
- Some objects must be unique across the whole system. This is the case
- for symbols and keywords. For these objects, Guile arranges to
- initialize them when the compilation unit is loaded, storing them into a
- slot in the image. References go indirectly through that slot.
- @code{static-ref} is used in this case.
- @deftypefn Instruction {} static-ref s24:@var{dst} r32:@var{offset}
- Load a @var{scm} value into @var{dst}. The @var{scm} value will be fetched from
- memory, @var{offset} 32-bit words away from the current instruction
- pointer. @var{offset} is a signed value.
- @end deftypefn
- Fields of non-immediates may need to be fixed up at load time, because
- we do not know in advance at what address they will be loaded. This is
- the case, for example, for a pair containing a non-immediate in one of
- its fields. @code{static-ref} and @code{static-patch!} are used in
- these situations.
- @deftypefn Instruction {} static-set! s24:@var{src} lo32:@var{offset}
- Store a @var{scm} value into memory, @var{offset} 32-bit words away from the
- current instruction pointer. @var{offset} is a signed value.
- @end deftypefn
- @deftypefn Instruction {} static-patch! x24:@var{_} lo32:@var{dst-offset} l32:@var{src-offset}
- Patch a pointer at @var{dst-offset} to point to @var{src-offset}. Both offsets
- are signed 32-bit values, indicating a memory address as a number
- of 32-bit words away from the current instruction pointer.
- @end deftypefn
- Many kinds of literals can be loaded with the above instructions, once
- the compiler has prepared the statically allocated data. This is the
- case for vectors, strings, uniform vectors, pairs, and procedures with
- no free variables. Other kinds of data might need special initializers;
- those instructions follow.
- @deftypefn Instruction {} string->number s12:@var{dst} s12:@var{src}
- Parse a string in @var{src} to a number, and store in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} string->symbol s12:@var{dst} s12:@var{src}
- Parse a string in @var{src} to a symbol, and store in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} symbol->keyword s12:@var{dst} s12:@var{src}
- Make a keyword from the symbol in @var{src}, and store it in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} load-typed-array s24:@var{dst} x8:@var{_} s24:@var{type} x8:@var{_} s24:@var{shape} n32:@var{offset} u32:@var{len}
- Load the contiguous typed array located at @var{offset} 32-bit words away
- from the instruction pointer, and store into @var{dst}. @var{len} is a byte
- length. @var{offset} is signed.
- @end deftypefn
- @node Dynamic Environment Instructions
- @subsubsection Dynamic Environment Instructions
- Guile's virtual machine has low-level support for @code{dynamic-wind},
- dynamic binding, and composable prompts and aborts.
- @deftypefn Instruction {} abort x24:@var{_}
- Abort to a prompt handler. The tag is expected in slot 1, and the rest
- of the values in the frame are returned to the prompt handler. This
- corresponds to a tail application of abort-to-prompt.
- If no prompt can be found in the dynamic environment with the given tag,
- an error is signalled. Otherwise all arguments are passed to the
- prompt's handler, along with the captured continuation, if necessary.
- If the prompt's handler can be proven to not reference the captured
- continuation, no continuation is allocated. This decision happens
- dynamically, at run-time; the general case is that the continuation may
- be captured, and thus resumed. A reinstated continuation will have its
- arguments pushed on the stack from slot 1, as if from a multiple-value
- return, and control resumes in the caller. Thus to the calling
- function, a call to @code{abort-to-prompt} looks like any other function
- call.
- @end deftypefn
- @deftypefn Instruction {} prompt s24:@var{tag} b1:@var{escape-only?} x7:@var{_} f24:@var{proc-slot} x8:@var{_} l24:@var{handler-offset}
- Push a new prompt on the dynamic stack, with a tag from @var{tag} and a
- handler at @var{handler-offset} words from the current @var{ip}.
- If an abort is made to this prompt, control will jump to the handler.
- The handler will expect a multiple-value return as if from a call with
- the procedure at @var{proc-slot}, with the reified partial continuation
- as the first argument, followed by the values returned to the handler.
- If control returns to the handler, the prompt is already popped off by
- the abort mechanism. (Guile's @code{prompt} implements Felleisen's
- @dfn{--F--} operator.)
- If @var{escape-only?} is nonzero, the prompt will be marked as
- escape-only, which allows an abort to this prompt to avoid reifying the
- continuation.
- @xref{Prompts}, for more information on prompts.
- @end deftypefn
- @deftypefn Instruction {} wind s12:@var{winder} s12:@var{unwinder}
- Push wind and unwind procedures onto the dynamic stack. Note that
- neither are actually called; the compiler should emit calls to wind and
- unwind for the normal dynamic-wind control flow. Also note that the
- compiler should have inserted checks that they wind and unwind procs are
- thunks, if it could not prove that to be the case. @xref{Dynamic Wind}.
- @end deftypefn
- @deftypefn Instruction {} unwind x24:@var{_}
- @var{a} normal exit from the dynamic extent of an expression. Pop the top
- entry off of the dynamic stack.
- @end deftypefn
- @deftypefn Instruction {} push-fluid s12:@var{fluid} s12:@var{value}
- Dynamically bind @var{value} to @var{fluid} by creating a with-fluids
- object and pushing that object on the dynamic stack. @xref{Fluids and
- Dynamic States}.
- @end deftypefn
- @deftypefn Instruction {} pop-fluid x24:@var{_}
- Leave the dynamic extent of a @code{with-fluid*} expression, restoring
- the fluid to its previous value. @code{push-fluid} should always be
- balanced with @code{pop-fluid}.
- @end deftypefn
- @deftypefn Instruction {} fluid-ref s12:@var{dst} s12:@var{src}
- Reference the fluid in @var{src}, and place the value in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} fluid-set s12:@var{fluid} s12:@var{val}
- Set the value of the fluid in @var{dst} to the value in @var{src}.
- @end deftypefn
- @deftypefn Instruction {} current-thread s24:@var{dst}
- Write the value of the current thread to @var{dst}.
- @end deftypefn
- @node Miscellaneous Instructions
- @subsubsection Miscellaneous Instructions
- @deftypefn Instruction {} halt x24:@var{_}
- Bring the VM to a halt, returning all the values from the stack. Used
- in the ``boot continuation'', which is used when entering the VM from C.
- @end deftypefn
- @deftypefn Instruction {} push s24:@var{src}
- Bump the stack pointer by one word, and fill it with the value from slot
- @var{src}. The offset to @var{src} is calculated before the stack
- pointer is adjusted.
- @end deftypefn
- The @code{push} instruction is used when another instruction is unable
- to address an operand because the operand is encoded with fewer than 24
- bits. In that case, Guile's assembler will transparently emit code that
- temporarily pushes any needed operands onto the stack, emits the
- original instruction to address those now-near variables, then shuffles
- the result (if any) back into place.
- @deftypefn Instruction {} pop s24:@var{dst}
- Pop the stack pointer, storing the value that was there in slot
- @var{dst}. The offset to @var{dst} is calculated after the stack
- pointer is adjusted.
- @end deftypefn
- @deftypefn Instruction {} drop c24:@var{count}
- Pop the stack pointer by @var{count} words, discarding any values that
- were stored there.
- @end deftypefn
- @node Inlined Scheme Instructions
- @subsubsection Inlined Scheme Instructions
- The Scheme compiler can recognize the application of standard Scheme
- procedures. It tries to inline these small operations to avoid the
- overhead of creating new stack frames. This allows the compiler to
- optimize better.
- @deftypefn Instruction {} make-vector s8:@var{dst} s8:@var{length} s8:@var{init}
- Make a vector and write it to @var{dst}. The vector will have space for
- @var{length} slots. They will be filled with the value in slot
- @var{init}.
- @end deftypefn
- @deftypefn Instruction {} make-vector/immediate s8:@var{dst} s8:@var{length} c8:@var{init}
- Make a short vector of known size and write it to @var{dst}. The vector
- will have space for @var{length} slots, an immediate value. They will
- be filled with the value in slot @var{init}.
- @end deftypefn
- @deftypefn Instruction {} vector-length s12:@var{dst} s12:@var{src}
- Store the length of the vector in @var{src} in @var{dst}, as an unboxed
- unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} vector-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- Fetch the item at position @var{idx} in the vector in @var{src}, and
- store it in @var{dst}. The @var{idx} value should be an unboxed
- unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} vector-ref/immediate s8:@var{dst} s8:@var{src} c8:@var{idx}
- Fill @var{dst} with the item @var{idx} elements into the vector at
- @var{src}. Useful for building data types using vectors.
- @end deftypefn
- @deftypefn Instruction {} vector-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- Store @var{src} into the vector @var{dst} at index @var{idx}. The
- @var{idx} value should be an unboxed unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} vector-set!/immediate s8:@var{dst} c8:@var{idx} s8:@var{src}
- Store @var{src} into the vector @var{dst} at index @var{idx}. Here
- @var{idx} is an immediate value.
- @end deftypefn
- @deftypefn Instruction {} struct-vtable s12:@var{dst} s12:@var{src}
- Store the vtable of @var{src} into @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} allocate-struct s8:@var{dst} s8:@var{vtable} s8:@var{nfields}
- Allocate a new struct with @var{vtable}, and place it in @var{dst}. The
- struct will be constructed with space for @var{nfields} fields, which
- should correspond to the field count of the @var{vtable}. The @var{idx}
- value should be an unboxed unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} struct-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- Fetch the item at slot @var{idx} in the struct in @var{src}, and store
- it in @var{dst}. The @var{idx} value should be an unboxed unsigned
- 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} struct-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- Store @var{src} into the struct @var{dst} at slot @var{idx}. The
- @var{idx} value should be an unboxed unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} allocate-struct/immediate s8:@var{dst} s8:@var{vtable} c8:@var{nfields}
- @deftypefnx Instruction {} struct-ref/immediate s8:@var{dst} s8:@var{src} c8:@var{idx}
- @deftypefnx Instruction {} struct-set!/immediate s8:@var{dst} c8:@var{idx} s8:@var{src}
- Variants of the struct instructions, but in which the @var{nfields} or
- @var{idx} fields are immediate values.
- @end deftypefn
- @deftypefn Instruction {} class-of s12:@var{dst} s12:@var{type}
- Store the vtable of @var{src} into @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} make-array s24:@var{dst} x8:@var{_} s24:@var{type} x8:@var{_} s24:@var{fill} x8:@var{_} s24:@var{bounds}
- Make a new array with @var{type}, @var{fill}, and @var{bounds}, storing it in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} string-length s12:@var{dst} s12:@var{src}
- Store the length of the string in @var{src} in @var{dst}, as an unboxed
- unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} string-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- Fetch the character at position @var{idx} in the string in @var{src},
- and store it in @var{dst}. The @var{idx} value should be an unboxed
- unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} cons s8:@var{dst} s8:@var{car} s8:@var{cdr}
- Cons @var{car} and @var{cdr}, and store the result in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} car s12:@var{dst} s12:@var{src}
- Place the car of @var{src} in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} cdr s12:@var{dst} s12:@var{src}
- Place the cdr of @var{src} in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} set-car! s12:@var{pair} s12:@var{car}
- Set the car of @var{dst} to @var{src}.
- @end deftypefn
- @deftypefn Instruction {} set-cdr! s12:@var{pair} s12:@var{cdr}
- Set the cdr of @var{dst} to @var{src}.
- @end deftypefn
- Note that @code{caddr} and friends compile to a series of @code{car}
- and @code{cdr} instructions.
- @node Inlined Mathematical Instructions
- @subsubsection Inlined Mathematical Instructions
- Inlining mathematical operations has the obvious advantage of handling
- fixnums without function calls or allocations. The trick, of course,
- is knowing when the result of an operation will be a fixnum, and there
- might be a couple bugs here.
- More instructions could be added here over time.
- All of these operations place their result in their first operand,
- @var{dst}.
- @deftypefn Instruction {} add s8:@var{dst} s8:@var{a} s8:@var{b}
- Add @var{a} to @var{b}.
- @end deftypefn
- @deftypefn Instruction {} add/immediate s8:@var{dst} s8:@var{src} c8:@var{imm}
- Add the unsigned integer @var{imm} to the value in @var{src}.
- @end deftypefn
- @deftypefn Instruction {} sub s8:@var{dst} s8:@var{a} s8:@var{b}
- Subtract @var{b} from @var{a}.
- @end deftypefn
- @deftypefn Instruction {} sub/immediate s8:@var{dst} s8:@var{src} s8:@var{imm}
- Subtract the unsigned integer @var{imm} from the value in @var{src}.
- @end deftypefn
- @deftypefn Instruction {} mul s8:@var{dst} s8:@var{a} s8:@var{b}
- Multiply @var{a} and @var{b}.
- @end deftypefn
- @deftypefn Instruction {} div s8:@var{dst} s8:@var{a} s8:@var{b}
- Divide @var{a} by @var{b}.
- @end deftypefn
- @deftypefn Instruction {} quo s8:@var{dst} s8:@var{a} s8:@var{b}
- Divide @var{a} by @var{b}.
- @end deftypefn
- @deftypefn Instruction {} rem s8:@var{dst} s8:@var{a} s8:@var{b}
- Divide @var{a} by @var{b}.
- @end deftypefn
- @deftypefn Instruction {} mod s8:@var{dst} s8:@var{a} s8:@var{b}
- Compute the modulo of @var{a} by @var{b}.
- @end deftypefn
- @deftypefn Instruction {} ash s8:@var{dst} s8:@var{a} s8:@var{b}
- Shift @var{a} arithmetically by @var{b} bits.
- @end deftypefn
- @deftypefn Instruction {} logand s8:@var{dst} s8:@var{a} s8:@var{b}
- Compute the bitwise @code{and} of @var{a} and @var{b}.
- @end deftypefn
- @deftypefn Instruction {} logior s8:@var{dst} s8:@var{a} s8:@var{b}
- Compute the bitwise inclusive @code{or} of @var{a} with @var{b}.
- @end deftypefn
- @deftypefn Instruction {} logxor s8:@var{dst} s8:@var{a} s8:@var{b}
- Compute the bitwise exclusive @code{or} of @var{a} with @var{b}.
- @end deftypefn
- @deftypefn Instruction {} logsub s8:@var{dst} s8:@var{a} s8:@var{b}
- Place the bitwise @code{and} of @var{a} and the bitwise @code{not} of
- @var{b} into @var{dst}.
- @end deftypefn
- @node Inlined Bytevector Instructions
- @subsubsection Inlined Bytevector Instructions
- Bytevector operations correspond closely to what the current hardware
- can do, so it makes sense to inline them to VM instructions, providing
- a clear path for eventual native compilation. Without this, Scheme
- programs would need other primitives for accessing raw bytes -- but
- these primitives are as good as any.
- @deftypefn Instruction {} bv-length s12:@var{dst} s12:@var{src}
- Store the length of the bytevector in @var{src} in @var{dst}, as an
- unboxed unsigned 64-bit integer.
- @end deftypefn
- @deftypefn Instruction {} bv-u8-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-s8-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-u16-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-s16-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-u32-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-s32-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-u64-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-s64-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-f32-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- @deftypefnx Instruction {} bv-f64-ref s8:@var{dst} s8:@var{src} s8:@var{idx}
- Fetch the item at byte offset @var{idx} in the bytevector @var{src}, and
- store it in @var{dst}. All accesses use native endianness.
- The @var{idx} value should be an unboxed unsigned 64-bit integer.
- The results are all written to the stack as unboxed values, either as
- signed 64-bit integers, unsigned 64-bit integers, or IEEE double
- floating point numbers.
- @end deftypefn
- @deftypefn Instruction {} bv-u8-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-s8-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-u16-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-s16-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-u32-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-s32-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-u64-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-s64-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-f32-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- @deftypefnx Instruction {} bv-f64-set! s8:@var{dst} s8:@var{idx} s8:@var{src}
- Store @var{src} into the bytevector @var{dst} at byte offset @var{idx}.
- Multibyte values are written using native endianness.
- The @var{idx} value should be an unboxed unsigned 64-bit integer.
- The @var{src} values are all unboxed, either as signed 64-bit integers,
- unsigned 64-bit integers, or IEEE double floating point numbers.
- @end deftypefn
- @node Unboxed Integer Arithmetic
- @subsubsection Unboxed Integer Arithmetic
- Guile supports two kinds of unboxed integers: unsigned 64-bit integers,
- and signed 64-bit integers. Guile prefers unsigned integers, in the
- sense that Guile's compiler supports them better and the virtual machine
- has more operations that work on them. Still, signed integers are
- supported at least to allow @code{bv-s64-ref} and related instructions
- to avoid boxing their values.
- @deftypefn Instruction {} scm->u64 s12:@var{dst} s12:@var{src}
- Unbox the SCM value at @var{src} to a unsigned 64-bit integer, placing
- the result in @var{dst}. If the @var{src} value is not an exact integer
- in the unsigned 64-bit range, signal an error.
- @end deftypefn
- @deftypefn Instruction {} u64->scm s12:@var{dst} s12:@var{src}
- Box the unsigned 64-bit integer at @var{src} to a SCM value and place
- the result in @var{dst}. The result will be a fixnum or a bignum.
- @end deftypefn
- @deftypefn Instruction {} load-u64 s24:@var{dst} au32:@var{high-bits} au32:@var{low-bits}
- Load a 64-bit value formed by joining @var{high-bits} and
- @var{low-bits}, and write it to @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} scm->s64 s12:@var{dst} s12:@var{src}
- @deftypefnx Instruction {} s64->scm s12:@var{dst} s12:@var{src}
- @deftypefnx Instruction {} load-s64 s24:@var{dst} as32:@var{high-bits} as32:@var{low-bits}
- Like @code{scm->u64}, @code{u64->scm}, and @code{load-u64}, but for
- signed 64-bit integers.
- @end deftypefn
- Sometimes the compiler can know that we will only need a subset of the
- bits in an integer. In that case we can sometimes unbox an integer even
- if it might be out of range.
- @deftypefn Instruction {} scm->u64/truncate s12:@var{dst} s12:@var{src}
- Take the SCM value in @var{dst} and @code{logand} it with @code{(1- (ash
- 1 64))}. Place the unboxed result in @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} br-if-u64-= s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-u64-< s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-u64-<= s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the unboxed unsigned 64-bit integer value in @var{a} is @code{=},
- @code{<}, or @code{<=} to the unboxed unsigned 64-bit integer value in
- @var{b}, respectively, add @var{offset} to the current instruction
- pointer.
- @end deftypefn
- @deftypefn Instruction {} br-if-u64-=-scm s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-u64-<-scm s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- @deftypefnx Instruction {} br-if-u64-<=-scm s24:@var{a} x8:@var{_} s24:@var{b} b1:@var{invert} x7:@var{_} l24:@var{offset}
- If the unboxed unsigned 64-bit integer value in @var{a} is @code{=},
- @code{<}, or @code{<=} to the SCM value in @var{b}, respectively, add
- @var{offset} to the current instruction pointer.
- @end deftypefn
- @deftypefn Instruction {} uadd s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} usub s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} umul s8:@var{dst} s8:@var{a} s8:@var{b}
- Like @code{add}, @code{sub}, and @code{mul}, except taking
- the operands as unboxed unsigned 64-bit integers, and producing the
- same. The result will be silently truncated to 64 bits.
- @end deftypefn
- @deftypefn Instruction {} uadd/immediate s8:@var{dst} s8:@var{a} c8:@var{b}
- @deftypefnx Instruction {} usub/immediate s8:@var{dst} s8:@var{a} c8:@var{b}
- @deftypefnx Instruction {} umul/immediate s8:@var{dst} s8:@var{a} c8:@var{b}
- Like @code{uadd}, @code{usub}, and @code{umul}, except the second
- operand is an immediate unsigned 8-bit integer.
- @end deftypefn
- @deftypefn Instruction {} ulogand s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} ulogior s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} ulogsub s8:@var{dst} s8:@var{a} s8:@var{b}
- Like @code{logand}, @code{logior}, and @code{logsub}, but operating on
- unboxed unsigned 64-bit integers.
- @end deftypefn
- @deftypefn Instruction {} ulsh s8:@var{dst} s8:@var{a} s8:@var{b}
- Shift the unboxed unsigned 64-bit integer in @var{a} left by @var{b}
- bits, also an unboxed unsigned 64-bit integer. Truncate to 64 bits and
- write to @var{dst} as an unboxed value. Only the lower 6 bits of
- @var{b} are used.
- @end deftypefn
- @deftypefn Instruction {} ursh s8:@var{dst} s8:@var{a} s8:@var{b}
- Like @code{ulsh}, but shifting right.
- @end deftypefn
- @deftypefn Instruction {} ulsh/immediate s8:@var{dst} s8:@var{a} c8:@var{b}
- @deftypefnx Instruction {} ursh/immediate s8:@var{dst} s8:@var{a} c8:@var{b}
- Like @code{ulsh} and @code{ursh}, but encoding @code{b} as an immediate
- 8-bit unsigned integer.
- @end deftypefn
- @node Unboxed Floating-Point Arithmetic
- @subsubsection Unboxed Floating-Point Arithmetic
- @deftypefn Instruction {} scm->f64 s12:@var{dst} s12:@var{src}
- Unbox the SCM value at @var{src} to an IEEE double, placing the result
- in @var{dst}. If the @var{src} value is not a real number, signal an
- error.
- @end deftypefn
- @deftypefn Instruction {} f64->scm s12:@var{dst} s12:@var{src}
- Box the IEEE double at @var{src} to a SCM value and place the result in
- @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} load-f64 s24:@var{dst} au32:@var{high-bits} au32:@var{low-bits}
- Load a 64-bit value formed by joining @var{high-bits} and
- @var{low-bits}, and write it to @var{dst}.
- @end deftypefn
- @deftypefn Instruction {} fadd s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} fsub s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} fmul s8:@var{dst} s8:@var{a} s8:@var{b}
- @deftypefnx Instruction {} fdiv s8:@var{dst} s8:@var{a} s8:@var{b}
- Like @code{add}, @code{sub}, @code{div}, and @code{mul}, except taking
- the operands as unboxed IEEE double floating-point numbers, and producing
- the same.
- @end deftypefn
|