summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-02-01 21:21:38 +0100
committerAndy Wingo <wingo@pobox.com>2016-02-01 21:21:38 +0100
commita653271f986316118961bb20f59f5c924b6cd523 (patch)
treeb695ac4042e63ab3649ed221b1393a37fabcc79e
parent5fceaed5e14086b0e0c7f91f58c2dd3392ecd9b9 (diff)
downloadguile-a653271f986316118961bb20f59f5c924b6cd523.tar.gz
Document new VM instructions
* doc/ref/vm.texi (Stack Layout): Add a note about unboxed values. (Instruction Set): Update for new instructions.
-rw-r--r--doc/ref/vm.texi231
1 files changed, 205 insertions, 26 deletions
diff --git a/doc/ref/vm.texi b/doc/ref/vm.texi
index 097fb8b75..528b66d92 100644
--- a/doc/ref/vm.texi
+++ b/doc/ref/vm.texi
@@ -189,6 +189,12 @@ 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
@@ -461,7 +467,7 @@ compiled @code{.go} files. It's good times!
@node Instruction Set
@subsection Instruction Set
-There are currently about 130 instructions in Guile's virtual machine.
+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.
@@ -551,6 +557,16 @@ 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::
@@ -564,6 +580,8 @@ implementations. For example, in the previous section we saw
* Inlined Scheme Instructions::
* Inlined Mathematical Instructions::
* Inlined Bytevector Instructions::
+* Unboxed Integer Arithmetic::
+* Unboxed Floating-Point Arithmetic::
@end menu
@@ -707,10 +725,8 @@ 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}. There is a short-cut in the single-value
-case, in that @code{return} handles the trivial shuffling itself. We
-start from slot 1 instead of slot 0 to make tail calls to @code{values}
-trivial.
+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.
@@ -772,10 +788,6 @@ 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 s24:@var{src}
-Return a value.
-@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,
@@ -935,6 +947,13 @@ not generated by the compiler.
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
@@ -990,10 +1009,9 @@ See @code{libguile/tags.h} for all the details.
@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}
-@deftypefnx Instruction {} br-if-equal 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?}, @code{eqv?}, or @code{equal?} to
-the value in @var{b}, respectively, add @var{offset} to the current
-instruction pointer.
+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}
@@ -1179,6 +1197,10 @@ Reference the fluid in @var{src}, and place the value in @var{dst}.
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
@@ -1234,12 +1256,14 @@ 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}.
+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}.
+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}
@@ -1248,7 +1272,8 @@ Fill @var{dst} with the item @var{idx} elements into the vector at
@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}.
+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}
@@ -1263,16 +1288,19 @@ Store the vtable of @var{src} into @var{dst}.
@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}.
+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}.
+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}.
+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}
@@ -1291,12 +1319,14 @@ Make a new array with @var{type}, @var{fill}, and @var{bounds}, storing it in @v
@end deftypefn
@deftypefn Instruction {} string-length s12:@var{dst} s12:@var{src}
-Store the length of the string in @var{src} in @var{dst}.
+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}.
+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}
@@ -1340,16 +1370,16 @@ All of these operations place their result in their first operand,
Add @var{a} to @var{b}.
@end deftypefn
-@deftypefn Instruction {} add1 s12:@var{dst} s12:@var{src}
-Add 1 to the value in @var{src}.
+@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 {} sub1 s12:@var{dst} s12:@var{src}
-Subtract 1 from @var{src}.
+@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}
@@ -1388,6 +1418,10 @@ Compute the bitwise inclusive @code{or} of @var{a} with @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
@@ -1398,6 +1432,11 @@ 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}
@@ -1411,6 +1450,12 @@ these primitives are as good as any.
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}
@@ -1426,4 +1471,138 @@ store it in @var{dst}. All accesses use native endianness.
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
+