Guile’s instruction set is low-level. This is good because the separate
components of, say, a vector-ref
operation might be able to be
optimized out, leaving only the operations that need to be performed at
run-time.
However some macro-operations may need to perform large amounts of computation at run-time to handle all the edge cases, and whose micro-operation components aren’t amenable to optimization. Residualizing code for the entire macro-operation would lead to code bloat with no benefit.
In this kind of a case, Guile’s VM calls out to intrinsics: run-time routines written in the host language (currently C, possibly more in the future if Guile gains more run-time targets like WebAssembly). There is one instruction for each instrinsic prototype; the intrinsic is specified by index in the instruction.
x24:_ c32:idx
¶Call the void
-returning instrinsic with index idx, passing
the current scm_thread*
as the argument.
s24:a c32:idx
¶Call the void
-returning instrinsic with index idx, passing
the current scm_thread*
and the scm
local a as
arguments.
s12:a s12:b c32:idx
¶Call the void
-returning instrinsic with index idx, passing
the current scm_thread*
and the scm
locals a and
b as arguments.
s12:a s12:b c32:idx
¶Call the void
-returning instrinsic with index idx, passing
the locals a, b, and c as arguments. a is a
scm
value, while b and c are raw u64
values
which fit into size_t
and uint32_t
types, respectively.
s24:dst c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
the current scm_thread*
as the argument. Place the result in
dst.
s12:dst s12:a c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
u64
local a as the argument. Place the result in
dst.
s12:dst s12:a c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
s64
local a as the argument. Place the result in
dst.
s12:dst s12:a c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
scm
local a as the argument. Place the result in
dst.
s12:dst s12:a c32:idx
¶Call the uint64_t
-returning instrinsic with index idx,
passing scm
local a as the argument. Place the u64
result in dst.
s12:dst s12:a c32:idx
¶Call the int64_t
-returning instrinsic with index idx,
passing scm
local a as the argument. Place the s64
result in dst.
s12:dst s12:a c32:idx
¶Call the double
-returning instrinsic with index idx,
passing scm
local a as the argument. Place the f64
result in dst.
s8:dst s8:a s8:b c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
scm
locals a and b as arguments. Place the
scm
result in dst.
s8:dst s8:a c8:b c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
scm
local a and uint8_t
immediate b as
arguments. Place the scm
result in dst.
s12:dst s12:a c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
the current scm_thread*
and scm
local a as
arguments. Place the scm
result in dst.
s8:dst s8:a s8:b c32:idx
¶Call the SCM
-returning instrinsic with index idx, passing
scm
local a and u64
local b as arguments.
Place the scm
result in dst.
s12:a s12:b c32:idx
¶Call the void
-returning instrinsic with index idx, passing
scm
locals a and b as arguments.
s8:a s8:b s8:c c32:idx
¶Call the void
-returning instrinsic with index idx, passing
scm
locals a, b, and c as arguments.
s8:a c8:b s8:c c32:idx
¶Call the void
-returning instrinsic with index idx, passing
scm
local a, uint8_t
immediate b, and
scm
local c as arguments.
There are corresponding macro-instructions for specific intrinsics.
These are equivalent to call-instrinsic-kind
instructions
with the appropriate intrinsic idx arguments.
Add SCM
values a and b and place the result in
dst.
Subtract SCM
value b from a and place the result in
dst.
Multiply SCM
values a and b and place the result in
dst.
Divide SCM
value a by b and place the result in
dst.
Compute the quotient of SCM
values a and b and place
the result in dst.
Compute the remainder of SCM
values a and b and place
the result in dst.
Compute the modulo of SCM
value a by b and place the
result in dst.
Compute the bitwise and
of SCM
values a and b
and place the result in dst.
Compute the bitwise inclusive or
of SCM
values a and
b and place the result in dst.
Compute the bitwise exclusive or
of SCM
values a and
b and place the result in dst.
Compute the bitwise and
of SCM
value a and the
bitwise not
of b and place the result in dst.
Shift SCM
value a left by u64
value b bits and
place the result in dst.
Shifts SCM
value a right by u64
value b bits
and place the result in dst.
Convert src to an unboxed f64
and place the result in
dst, or raises an error if src is not a real number.
Convert src to an unboxed u64
and place the result in
dst, or raises an error if src is not an integer within
range.
Convert src to an unboxed u64
and place the result in
dst, truncating to the low 64 bits, or raises an error if
src is not an integer.
Convert src to an unboxed s64
and place the result in
dst, or raises an error if src is not an integer within
range.
Convert u64 value src to a Scheme integer in dst.
Convert s64 value src to a Scheme integer in dst.
Sets the character idx (a u64
) of string str to
ch (a u64
that is a valid character value).
Call string->number
on src and place the result in
dst.
Call string->symbol
on src and place the result in
dst.
Call symbol->keyword
on src and place the result in
dst.
Set dst to the GOOPS class of src
.
Push wind and unwind procedures onto the dynamic stack. Note that neither are actually called; the compiler should emit calls to winder and unwinder for the normal dynamic-wind control flow. Also note that the compiler should have inserted checks that winder and unwinder are thunks, if it could not prove that to be the case. See Dynamic Wind.
Exit from the dynamic extent of an expression, popping the top entry off of the dynamic stack.
Dynamically bind value to fluid by creating a with-fluids object, pushing that object on the dynamic stack. See Fluids and Dynamic States.
Leave the dynamic extent of a with-fluid*
expression, restoring
the fluid to its previous value. push-fluid
should always be
balanced with pop-fluid
.
Place the value associated with the fluid fluid in dst.
Set the value of the fluid fluid to value.
Save the current set of fluid bindings on the dynamic stack and instate the bindings from state instead. See Fluids and Dynamic States.
Restore a saved set of fluid bindings from the dynamic stack.
push-dynamic-state
should always be balanced with
pop-dynamic-state
.
Look up the module named name, resolve its public interface if the immediate operand public? is true, then place the result in dst.
Look up sym in module mod, placing the resulting variable
(or #f
if not found) in dst.
Look up sym in module mod, placing the resulting variable in dst, creating the variable if needed.
Set dst to the current module.
Intrinsics for use by the baseline compiler. The usual strategy for CPS
compilation is to expose the component parts of e.g. vector-ref
so that the compiler can learn from them and eliminate needless bits.
However in the non-optimizing baseline compiler, that’s just overhead,
so we have some intrinsics that encapsulate all the usual type checks.