mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-27 23:40:24 +02:00
update manual for jit_allocai
git-archimport-id: bonzini@gnu.org--2004b/lightning--stable--1.2--patch-38
This commit is contained in:
parent
82d90f4ddc
commit
f748b3c5e7
3 changed files with 92 additions and 47 deletions
4
NEWS
4
NEWS
|
@ -5,6 +5,10 @@ o Initial support for x86-64 back-end.
|
|||
|
||||
o Many bug fixes.
|
||||
|
||||
o jit_pushr/jit_popr are deprecated, you need to #define
|
||||
JIT_NEED_PUSH_POP prior to including lightning.h if you
|
||||
want to use them.
|
||||
|
||||
o Support for stack-allocated variables. Because of this,
|
||||
backends defining JIT_FP should now rename it to JIT_AP.
|
||||
JIT_FP is now a user-visible register used in ldxi/ldxr
|
||||
|
|
|
@ -858,7 +858,7 @@ operations:
|
|||
@section Macros composing the platform-independent layer
|
||||
|
||||
@table @b
|
||||
@item Register names (all mandatory but the last two)
|
||||
@item Register names (all mandatory but the last three)
|
||||
@example
|
||||
#define JIT_R
|
||||
#define JIT_R_NUM
|
||||
|
@ -866,6 +866,7 @@ operations:
|
|||
#define JIT_V_NUM
|
||||
#define JIT_FPR
|
||||
#define JIT_FPR_NUM
|
||||
#define JIT_FP
|
||||
#define JIT_SP
|
||||
#define JIT_AP
|
||||
#define JIT_RZERO
|
||||
|
@ -878,6 +879,7 @@ operations:
|
|||
|
||||
@item Mandatory:
|
||||
@example
|
||||
#define jit_allocai()
|
||||
#define jit_arg_c()
|
||||
#define jit_arg_i()
|
||||
#define jit_arg_l()
|
||||
|
@ -1022,11 +1024,9 @@ operations:
|
|||
#define jit_orr_i(d, s1, s2)
|
||||
#define jit_patch_at(jump_pc, value)
|
||||
#define jit_patch_movi(jump_pc, value)
|
||||
#define jit_pop_i(rs)
|
||||
#define jit_prepare_d(numargs)
|
||||
#define jit_prepare_f(numargs)
|
||||
#define jit_prepare_i(numargs)
|
||||
#define jit_push_i(rs)
|
||||
#define jit_pusharg_i(rs)
|
||||
#define jit_ret()
|
||||
#define jit_retval_i(rd)
|
||||
|
@ -1242,10 +1242,6 @@ operations:
|
|||
#define jit_ori_ul(d, rs, is)
|
||||
#define jit_orr_ui(d, s1, s2)
|
||||
#define jit_orr_ul(d, s1, s2)
|
||||
#define jit_pop_ui(rs)
|
||||
#define jit_pop_ul(rs)
|
||||
#define jit_push_ui(rs)
|
||||
#define jit_push_ul(rs)
|
||||
#define jit_pusharg_c(rs)
|
||||
#define jit_pusharg_p(rs)
|
||||
#define jit_pusharg_s(rs)
|
||||
|
@ -1478,8 +1474,6 @@ operations:
|
|||
#define jit_ner_l(d, s1, s2)
|
||||
#define jit_ori_l(d, rs, is)
|
||||
#define jit_orr_l(d, s1, s2)
|
||||
#define jit_pop_l(rs)
|
||||
#define jit_push_l(rs)
|
||||
#define jit_pusharg_l(rs)
|
||||
#define jit_retval_l(rd)
|
||||
#define jit_rshi_l(d, rs, is)
|
||||
|
|
123
doc/using.texi
123
doc/using.texi
|
@ -90,10 +90,9 @@ is equivalent to @code{i} on 32-bit machines, and @code{p} is
|
|||
substantially equivalent to @code{ul}).
|
||||
|
||||
There are at least seven integer registers, of which six are
|
||||
general-purpose, while the last is used to contain the stack pointer
|
||||
(@code{SP}). The stack pointer can be used to allocate and access local
|
||||
variables on the stack (which is supposed to grow downwards in memory
|
||||
on all architectures).
|
||||
general-purpose, while the last is used to contain the frame pointer
|
||||
(@code{FP}). The frame pointer can be used to allocate and access local
|
||||
variables on the stack, using the @code{allocai} instruction.
|
||||
|
||||
Of the general-purpose registers, at least three are guaranteed to be
|
||||
preserved across function calls (@code{V0}, @code{V1} and
|
||||
|
@ -271,15 +270,6 @@ stxr c uc s us i ui l ul p f d *(O1+O2) = O3
|
|||
stxi c uc s us i ui l ul p f d *(O1+O2) = O3
|
||||
@end example
|
||||
|
||||
@item Stack management
|
||||
These accept a single register parameter. These operations are not
|
||||
guaranteed to be efficient on all architectures.
|
||||
|
||||
@example
|
||||
pushr i ui l ul p @r{push }O1@r{ on the stack}
|
||||
popr i ui l ul p @r{pop }O1@r{ off the stack}
|
||||
@end example
|
||||
|
||||
@item Argument management
|
||||
These are:
|
||||
@example
|
||||
|
@ -388,16 +378,13 @@ These accept one argument except @code{ret} which has none; the
|
|||
difference between @code{finish} and @code{calli} is that the
|
||||
latter does not clean the stack from pushed parameters (if any)
|
||||
and the former must @strong{always} follow a @code{prepare}
|
||||
instruction. Results are undefined when using function calls
|
||||
in a leaf function.
|
||||
instruction.
|
||||
@example
|
||||
calli (not specified) @r{function call to O1}
|
||||
callr (not specified) @r{function call to a register}
|
||||
finish (not specified) @r{function call to O1}
|
||||
finishr (not specified) @r{function call to a register}
|
||||
jmpi/jmpr (not specified) @r{unconditional jump to O1}
|
||||
prolog (not specified) @r{function prolog for O1 args}
|
||||
leaf (not specified) @r{the same for leaf functions}
|
||||
ret (not specified) @r{return from subroutine}
|
||||
retval c uc s us i ui l ul p f d @r{move return value}
|
||||
@r{to register}
|
||||
|
@ -407,6 +394,26 @@ Like branch instruction, @code{jmpi} also returns a value which is to
|
|||
be used to compile forward branches. @xref{Fibonacci, , Fibonacci
|
||||
numbers}.
|
||||
|
||||
@item Function prolog
|
||||
|
||||
These macros are used to set up the function prolog, in particular to
|
||||
declare the number of arguments accepted by a function, and to reserve
|
||||
space on the stack to be used for variables. They accept a single
|
||||
numeric argument.
|
||||
|
||||
@example
|
||||
prolog (not specified) @r{function prolog for O1 args}
|
||||
leaf (not specified) @r{the same for leaf functions}
|
||||
allocai (not specified) @r{reserve space on the stack}
|
||||
@end example
|
||||
|
||||
Results are undefined when using function calls in a leaf function.
|
||||
|
||||
@code{allocai} receives the number of bytes to allocate and returns
|
||||
the offset from the frame pointer register @code{FP} to the base of
|
||||
the area. The area is aligned to an @code{int}; future versions of
|
||||
@lightning{} may provide more fine-grained control on the alignment of
|
||||
stack-allocated variables.
|
||||
@end table
|
||||
|
||||
As a small appetizer, here is a small function that adds 1 to the input
|
||||
|
@ -740,39 +747,72 @@ and is able to compile different formulas to different functions.
|
|||
Here is the code for the expression compiler; a sample usage will
|
||||
follow.
|
||||
|
||||
Since @lightning{} does not provide push/pop instruction, this
|
||||
example uses a stack-allocated area to store the data. Such an
|
||||
area can be allocated using the macro @code{jit_allocai}, which
|
||||
receives the number of bytes to allocate and returns the offset
|
||||
from the frame pointer register @code{JIT_FP} to the base of the
|
||||
area. The area is aligned to an @code{int}; future versions
|
||||
of @lightning{} may provide more fine-grained control on the
|
||||
alignment of stack-allocated variables.
|
||||
|
||||
Usually, you will use the @code{ldxi} and @code{stxi} instruction
|
||||
to access stack-allocated variables. However, it is possible to
|
||||
use operations such as @code{add} to compute the address of the
|
||||
variables, and pass the address around.
|
||||
|
||||
@example
|
||||
#include <stdio.h>
|
||||
#include "lightning.h"
|
||||
|
||||
typedef int (*pifi)(int); @rem{/* Pointer to Int Function of Int */}
|
||||
|
||||
void stack_push(int reg, int *sp)
|
||||
{
|
||||
jit_stxi_i (*sp, JIT_FP, reg);
|
||||
*sp += sizeof (int);
|
||||
}
|
||||
|
||||
void stack_pop(int reg, int *sp)
|
||||
{
|
||||
*sp -= sizeof (int);
|
||||
jit_ldxi_i (reg, JIT_FP, *sp);
|
||||
}
|
||||
|
||||
pifi compile_rpn(char *expr)
|
||||
@{
|
||||
pifi fn;
|
||||
int stack_base, stack_ptr;
|
||||
int in;
|
||||
|
||||
fn = (pifi) (jit_get_ip().iptr);
|
||||
jit_leaf(1);
|
||||
in = jit_arg_i();
|
||||
jit_getarg_i(JIT_R0, in);
|
||||
stack_ptr = stack_base = jit_allocai (32 * sizeof (int));
|
||||
|
||||
jit_getarg_i(JIT_R2, in);
|
||||
|
||||
while (*expr) @{
|
||||
char buf[32];
|
||||
int n;
|
||||
if (sscanf(expr, "%[0-9]%n", buf, &n)) @{
|
||||
expr += n - 1;
|
||||
jit_push_i(JIT_R0);
|
||||
stack_push(JIT_R0, &stack_ptr);
|
||||
jit_movi_i(JIT_R0, atoi(buf));
|
||||
@} else if (*expr == 'x') @{
|
||||
stack_push(JIT_R0, &stack_ptr);
|
||||
jit_movi_i(JIT_R0, JIT_R2);
|
||||
@} else if (*expr == '+') @{
|
||||
jit_pop_i(JIT_R1);
|
||||
stack_pop(JIT_R1, &stack_ptr);
|
||||
jit_addr_i(JIT_R0, JIT_R1, JIT_R0);
|
||||
@} else if (*expr == '-') @{
|
||||
jit_pop_i(JIT_R1);
|
||||
stack_pop(JIT_R1, &stack_ptr);
|
||||
jit_subr_i(JIT_R0, JIT_R1, JIT_R0);
|
||||
@} else if (*expr == '*') @{
|
||||
jit_pop_i(JIT_R1);
|
||||
stack_pop(JIT_R1, &stack_ptr);
|
||||
jit_mulr_i(JIT_R0, JIT_R1, JIT_R0);
|
||||
@} else if (*expr == '/') @{
|
||||
jit_pop_i(JIT_R1);
|
||||
stack_pop(JIT_R1, &stack_ptr);
|
||||
jit_divr_i(JIT_R0, JIT_R1, JIT_R0);
|
||||
@} else @{
|
||||
fprintf(stderr, "cannot compile: %s\n", expr);
|
||||
|
@ -786,13 +826,20 @@ pifi compile_rpn(char *expr)
|
|||
@}
|
||||
@end example
|
||||
|
||||
The principle on which the calculator is based is easy: the stack
|
||||
top is held in R0, while the remaining items of the stack are held
|
||||
on the hardware stack. Compiling an operand pushes the old stack
|
||||
top onto the stack and moves the operand into R0; compiling an
|
||||
operator pops the second operand off the stack into R1, and
|
||||
compiles the operation so that the result goes into R0, thus
|
||||
becoming the new stack top.
|
||||
The principle on which the calculator is based is easy: the stack top
|
||||
is held in R0, while the remaining items of the stack are held in the
|
||||
memory area that we allocate with @code{allocai}. Compiling a numeric
|
||||
operand or the argument @code{x} pushes the old stack top onto the
|
||||
stack and moves the operand into R0; compiling an operator pops the
|
||||
second operand off the stack into R1, and compiles the operation so
|
||||
that the result goes into R0, thus becoming the new stack top.
|
||||
|
||||
This example allocates a fixed area for 32 @code{int}s. This is not
|
||||
a problem when the function is a leaf like in this case; in a full-blown
|
||||
compiler you will want to analyze the input and determine the number
|
||||
of needed stack slots---a very simple example of register allocation.
|
||||
The area is then managed like a stack using @code{stack_push} and
|
||||
@code{stack_pop}.
|
||||
|
||||
Try to locate a call to @code{jit_set_ip} in the source code. You
|
||||
will not find one; this means that the client has to manually set
|
||||
|
@ -814,8 +861,8 @@ int main()
|
|||
int i;
|
||||
|
||||
jit_set_ip(codeBuffer);
|
||||
c2f = compile_rpn("9*5/32+");
|
||||
f2c = compile_rpn("32-5*9/");
|
||||
c2f = compile_rpn("32x9*5/+");
|
||||
f2c = compile_rpn("x32-5*9/");
|
||||
jit_flush_code(codeBuffer, jit_get_ip().ptr);
|
||||
|
||||
printf("\nC:");
|
||||
|
@ -845,9 +892,9 @@ generation so powerful.
|
|||
|
||||
The @file{rpn.c} file in the @lightning{} distribution includes a more
|
||||
complete (and more complex) implementation of @code{compile_rpn},
|
||||
which does constant folding, allows the argument to the functions
|
||||
to be used more than once, and is able to assemble instructions with
|
||||
an immediate parameter.
|
||||
which does constant folding and is able to assemble instructions with
|
||||
an immediate parameter. Still, it is based on the same principle and
|
||||
also uses @code{allocai} to allocate space for the stack.
|
||||
|
||||
@node Fibonacci
|
||||
@section Fibonacci numbers
|
||||
|
@ -1160,9 +1207,9 @@ extern void _opt_muli_i(struct jit_state *, int, int, int);
|
|||
@section Registers
|
||||
@chapter Accessing the whole register file
|
||||
|
||||
As mentioned earlier in this chapter, all @lightning{} back-ends
|
||||
are guaranteed to have at least six integer registers and six
|
||||
floating-point registers, but many back-ends will have more.
|
||||
As mentioned earlier in this chapter, all @lightning{} back-ends are
|
||||
guaranteed to have at least six general-purpose integer registers and
|
||||
six floating-point registers, but many back-ends will have more.
|
||||
|
||||
To access the entire register files, you can use the
|
||||
@code{JIT_R}, @code{JIT_V} and @code{JIT_FPR} macros. They
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue