started x86 compiler

cvs
Slava Pestov 2004-09-06 06:32:04 +00:00
parent 9d9643850e
commit ea3ad6f14f
19 changed files with 212 additions and 15 deletions

View File

@ -1,6 +1,16 @@
CC = gcc CC = gcc
# On PowerPC G5:
# CFLAGS = -mcpu=970 -mtune=970 -mpowerpc64 -ffast-math -O3
# On Pentium 4:
# CFLAGS = -march=pentium4 -ffast-math -O3
# Add -fomit-frame-pointer if you don't care about debugging
CFLAGS = -Os -g -Wall CFLAGS = -Os -g -Wall
# On Solaris:
# LIBS = -lsocket -lnsl -lm
LIBS = -lm LIBS = -lm
STRIP = strip STRIP = strip
OBJS = native/arithmetic.o native/array.o native/bignum.o \ OBJS = native/arithmetic.o native/array.o native/bignum.o \
@ -14,10 +24,10 @@ OBJS = native/arithmetic.o native/array.o native/bignum.o \
native/run.o \ native/run.o \
native/sbuf.o native/socket.o native/stack.o \ native/sbuf.o native/socket.o native/stack.o \
native/string.o native/types.o native/vector.o \ native/string.o native/types.o native/vector.o \
native/write.o native/word.o native/write.o native/word.o native/compiler.o
f: $(OBJS) f: $(OBJS)
$(CC) $(LIBS) -o $@ $(OBJS) $(CC) $(LIBS) $(CFLAGS) -o $@ $(OBJS)
# $(STRIP) $@ # $(STRIP) $@
clean: clean:

View File

@ -8,7 +8,7 @@
- jedit ==> jedit-word, jedit takes a file name - jedit ==> jedit-word, jedit takes a file name
- introduce ifte* and ?str-head/?str-tail where appropriate - introduce ifte* and ?str-head/?str-tail where appropriate
- namespace clone drops static var bindings - namespace clone drops static var bindings
- solaris: -lsocket -lnsl <kc5tja> The binary register ordering, from 0 to 7, is EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI.
+ bignums: + bignums:

View File

@ -2351,17 +2351,32 @@ Notice that until now, all the code except a handful of examples has only used t
Variables are typically used for longer-term storage of data, and for temporary storage of objects that are being constructed, where using the stack would be ackward. Another use for variables is compound data structures, realized as nested namespaces of variables. This concept should be instantly familiar to anybody who's used an object-oriented programming language. Variables are typically used for longer-term storage of data, and for temporary storage of objects that are being constructed, where using the stack would be ackward. Another use for variables is compound data structures, realized as nested namespaces of variables. This concept should be instantly familiar to anybody who's used an object-oriented programming language.
The words \texttt{get ( name -{}- value )} and \texttt{set ( value name -{}- )} retreive and store variable values, respectively. For example: The words \texttt{get ( name -{}- value )} and \texttt{set ( value name -{}- )} retreive and store variable values, respectively. Variable names are strings, and they do not have to be declared before use. For example:
blah blah \begin{alltt}
5 "x" set
"x" get .
\emph{5}
\end{alltt}
\subsection{Namespaces} \subsection{Namespaces}
describe bind and extend combinators Only having one list of variable name/value bindings would make the language terribly inflexible. Instead, a variable has any number of potential values, one per namespace. There is a notion of a ``current namespace''; the \texttt{set} word always stores variables in the current namespace. On the other hand, \texttt{get} traverses up the stack of namespace bindings until it finds a variable with the specified name.
namespaces are hashtables \texttt{bind ( namespace quot -{}- )} executes a quotation in the dynamic scope of a namespace. For example, the following sets the value of \texttt{x} to 5 in the global namespace, regardless of the current namespace at the time the word was called.
values, vars, vars-values \begin{alltt}
: global-example ( -- )
global {[} 5 "x" set {]} bind ;
\end{alltt}
\texttt{<namespace> ( -{}- namespace )} creates a new namespace object. Actually, a namespace is just a hashtable, with a default capacity.
\texttt{with-scope ( quot -{}- )} combines \texttt{<namespace>} with \texttt{bind} by executing a quotation in a new namespace.
get example
describe
\subsection{The name stack} \subsection{The name stack}

View File

@ -41,6 +41,11 @@ USE: vectors
USE: vectors USE: vectors
USE: words USE: words
IN: compiler
DEFER: compile-byte
DEFER: compile-cell
DEFER: compile-offset
IN: kernel IN: kernel
DEFER: getenv DEFER: getenv
DEFER: setenv DEFER: setenv
@ -106,6 +111,8 @@ DEFER: (random-int)
IN: words IN: words
DEFER: <word> DEFER: <word>
DEFER: word-hashcode DEFER: word-hashcode
DEFER: word-xt
DEFER: set-word-xt
DEFER: word-primitive DEFER: word-primitive
DEFER: set-word-primitive DEFER: set-word-primitive
DEFER: word-parameter DEFER: word-parameter
@ -205,6 +212,8 @@ IN: cross-compiler
word? word?
<word> <word>
word-hashcode word-hashcode
word-xt
set-word-xt
word-primitive word-primitive
set-word-primitive set-word-primitive
word-parameter word-parameter
@ -268,6 +277,9 @@ IN: cross-compiler
dump dump
cwd cwd
cd cd
compile-byte
compile-cell
compile-offset
] [ ] [
swap succ tuck primitive, swap succ tuck primitive,
] each drop ; ] each drop ;

View File

@ -109,6 +109,7 @@ USE: stdio
"/library/telnetd.factor" "/library/telnetd.factor"
"/library/inferior.factor" "/library/inferior.factor"
"/library/platform/native/profiler.factor" "/library/platform/native/profiler.factor"
"/library/platform/native/compiler.factor"
"/library/image.factor" "/library/image.factor"
"/library/cross-compiler.factor" "/library/cross-compiler.factor"

View File

@ -0,0 +1,90 @@
IN: compiler
USE: math
USE: stack
USE: lists
USE: combinators
USE: words
USE: namespaces
USE: unparser
USE: errors
USE: strings
USE: logic
USE: kernel
: DATASTACK
#! A pointer to a pointer to the datastack top.
11 getenv ;
: EAX 0 ;
: ECX 1 ;
: EDX 2 ;
: EBX 3 ;
: ESP 4 ;
: EBP 5 ;
: ESI 6 ;
: EDI 7 ;
: I>R ( imm reg -- )
#! MOV <imm> TO <reg>
HEX: a1 + compile-byte compile-cell ;
: I>[R] ( imm reg -- )
#! MOV <imm> TO ADDRESS <reg>
HEX: c7 compile-byte compile-byte compile-cell ;
: I+[I] ( imm addr -- )
#! ADD <imm> TO ADDRESS <addr>
HEX: 81 compile-byte
HEX: 05 compile-byte
compile-cell
compile-cell ;
: LITERAL ( cell -- )
#! Push literal on data stack.
DATASTACK EAX I>R EAX I>[R] 4 DATASTACK I+[I] ;
: (JMP) ( xt opcode -- )
#! JMP, CALL insn is 5 bytes long
#! addr is relative to *after* insn
compile-byte compile-offset 4 + - compile-cell ;
: JMP HEX: e9 (JMP) ;
: CALL HEX: e8 (JMP) ;
: RET HEX: c3 compile-byte ;
: compile-word ( word -- )
#! Compile a JMP at the end (tail call optimization)
word-xt "compile-last" get [ JMP ] [ CALL ] ifte ;
: compile-fixnum ( n -- )
3 shift 7 bitnot bitand LITERAL ;
: compile-atom ( obj -- )
[
[ fixnum? ] [ compile-fixnum ]
[ word? ] [ compile-word ]
[ drop t ] [ "Cannot compile " swap unparse cat2 throw ]
] cond ;
: compile-loop ( quot -- )
dup [
unswons
over not "compile-last" set
compile-atom
compile-loop
] [
drop RET
] ifte ;
: compile-quot ( quot -- xt )
[
"compile-last" off
compile-offset swap compile-loop
] with-scope ;
: compile ( word -- )
intern dup word-parameter compile-quot swap set-word-xt ;
: call-xt ( xt -- )
#! For testing.
0 f f <word> [ set-word-xt ] keep execute ;

View File

@ -8,7 +8,7 @@ CELL tag_integer(FIXNUM x)
return tag_fixnum(x); return tag_fixnum(x);
} }
CELL tag_unsigned_integer(CELL x) CELL tag_cell(CELL x)
{ {
if(x > FIXNUM_MAX) if(x > FIXNUM_MAX)
return tag_object(s48_ulong_to_bignum(x)); return tag_object(s48_ulong_to_bignum(x));
@ -16,6 +16,20 @@ CELL tag_unsigned_integer(CELL x)
return tag_fixnum(x); return tag_fixnum(x);
} }
CELL to_cell(CELL x)
{
switch(type_of(x))
{
case FIXNUM_TYPE:
return untag_fixnum_fast(x);
case BIGNUM_TYPE:
/* really need bignum_to_ulong! */
return s48_bignum_to_long(untag_bignum(x));
default:
type_error(INTEGER_TYPE,x);
}
}
CELL upgraded_arithmetic_type(CELL type1, CELL type2) CELL upgraded_arithmetic_type(CELL type1, CELL type2)
{ {
switch(type1) switch(type1)

View File

@ -3,7 +3,8 @@
CELL upgraded_arithmetic_type(CELL type1, CELL type2); CELL upgraded_arithmetic_type(CELL type1, CELL type2);
CELL tag_integer(FIXNUM x); CELL tag_integer(FIXNUM x);
CELL tag_unsigned_integer(CELL x); CELL tag_cell(CELL x);
CELL to_cell(CELL x);
#define BINARY_OP(OP) \ #define BINARY_OP(OP) \
CELL OP(CELL x, CELL y) \ CELL OP(CELL x, CELL y) \

23
native/compiler.c Normal file
View File

@ -0,0 +1,23 @@
#include "factor.h"
void init_compiler(void)
{
init_zone(&compiling,COMPILE_ZONE_SIZE);
}
void primitive_compile_byte(void)
{
bput(compiling.here,to_fixnum(dpop()));
compiling.here++;
}
void primitive_compile_cell(void)
{
put(compiling.here,to_cell(dpop()));
compiling.here += sizeof(CELL);
}
void primitive_compile_offset(void)
{
dpush(tag_integer(compiling.here));
}

6
native/compiler.h Normal file
View File

@ -0,0 +1,6 @@
ZONE compiling;
void init_compiler(void);
void primitive_compile_byte(void);
void primitive_compile_cell(void);
void primitive_compile_offset(void);

View File

@ -17,6 +17,7 @@ int main(int argc, char** argv)
init_stacks(); init_stacks();
init_io(); init_io();
init_signals(); init_signals();
init_compiler();
args = F; args = F;
while(--argc != 0) while(--argc != 0)

View File

@ -42,6 +42,7 @@ typedef unsigned char BYTE;
/* Memory heap size */ /* Memory heap size */
#define DEFAULT_ARENA (5 * 1024 * 1024) #define DEFAULT_ARENA (5 * 1024 * 1024)
#define COMPILE_ZONE_SIZE (5 * 1024 * 1024)
#define STACK_SIZE 16384 #define STACK_SIZE 16384
@ -79,5 +80,6 @@ and allows profiling. */
#include "primitives.h" #include "primitives.h"
#include "vector.h" #include "vector.h"
#include "stack.h" #include "stack.h"
#include "compiler.h"
#endif /* __FACTOR_H__ */ #endif /* __FACTOR_H__ */

View File

@ -21,7 +21,7 @@ void* alloc_guarded(CELL size)
void init_zone(ZONE* z, CELL size) void init_zone(ZONE* z, CELL size)
{ {
z->base = z->here = align8((CELL)malloc(size)); z->base = z->here = align8((CELL)alloc_guarded(size));
if(z->base == 0) if(z->base == 0)
fatal_error("Cannot allocate zone",size); fatal_error("Cannot allocate zone",size);
z->limit = z->base + size; z->limit = z->base + size;

View File

@ -88,6 +88,8 @@ XT primitives[] = {
primitive_wordp, primitive_wordp,
primitive_word, primitive_word,
primitive_word_hashcode, primitive_word_hashcode,
primitive_word_xt,
primitive_set_word_xt,
primitive_word_primitive, primitive_word_primitive,
primitive_set_word_primitive, primitive_set_word_primitive,
primitive_word_parameter, primitive_word_parameter,
@ -150,7 +152,10 @@ XT primitives[] = {
primitive_set_word_allot_count, primitive_set_word_allot_count,
primitive_dump, primitive_dump,
primitive_cwd, primitive_cwd,
primitive_cd primitive_cd,
primitive_compile_byte,
primitive_compile_cell,
primitive_compile_offset
}; };
CELL primitive_to_xt(CELL primitive) CELL primitive_to_xt(CELL primitive)

View File

@ -1,4 +1,4 @@
extern XT primitives[]; extern XT primitives[];
#define PRIMITIVE_COUNT 150 #define PRIMITIVE_COUNT 155
CELL primitive_to_xt(CELL primitive); CELL primitive_to_xt(CELL primitive);

View File

@ -11,6 +11,8 @@
#define BOOT_ENV 8 #define BOOT_ENV 8
#define RUNQUEUE_ENV 9 /* used by library only */ #define RUNQUEUE_ENV 9 /* used by library only */
#define ARGS_ENV 10 #define ARGS_ENV 10
#define DS_ENV 11 /* ptr to base addr of datastack */
#define CS_ENV 12 /* ptr to base addr of callstack */
/* Profiling timer */ /* Profiling timer */
struct itimerval prof_timer; struct itimerval prof_timer;

View File

@ -14,8 +14,10 @@ void init_stacks(void)
{ {
ds_bot = (CELL)alloc_guarded(STACK_SIZE); ds_bot = (CELL)alloc_guarded(STACK_SIZE);
reset_datastack(); reset_datastack();
userenv[DS_ENV] = tag_integer((CELL)&ds);
cs_bot = (CELL)alloc_guarded(STACK_SIZE); cs_bot = (CELL)alloc_guarded(STACK_SIZE);
reset_callstack(); reset_callstack();
userenv[CS_ENV] = tag_integer((CELL)&cs);
callframe = userenv[BOOT_ENV]; callframe = userenv[BOOT_ENV];
} }

View File

@ -42,6 +42,17 @@ void primitive_word_hashcode(void)
drepl(tag_fixnum(untag_word(dpeek())->hashcode)); drepl(tag_fixnum(untag_word(dpeek())->hashcode));
} }
void primitive_word_xt(void)
{
drepl(tag_cell(untag_word(dpeek())->xt));
}
void primitive_set_word_xt(void)
{
WORD* word = untag_word(dpop());
word->xt = to_cell(dpop());
}
void primitive_word_primitive(void) void primitive_word_primitive(void)
{ {
drepl(tag_fixnum(untag_word(dpeek())->primitive)); drepl(tag_fixnum(untag_word(dpeek())->primitive));
@ -78,7 +89,7 @@ void primitive_set_word_plist(void)
void primitive_word_call_count(void) void primitive_word_call_count(void)
{ {
drepl(tag_unsigned_integer(untag_word(dpeek())->call_count)); drepl(tag_cell(untag_word(dpeek())->call_count));
} }
void primitive_set_word_call_count(void) void primitive_set_word_call_count(void)
@ -89,7 +100,7 @@ void primitive_set_word_call_count(void)
void primitive_word_allot_count(void) void primitive_word_allot_count(void)
{ {
drepl(tag_unsigned_integer(untag_word(dpeek())->allot_count)); drepl(tag_cell(untag_word(dpeek())->allot_count));
} }
void primitive_set_word_allot_count(void) void primitive_set_word_allot_count(void)

View File

@ -37,6 +37,8 @@ void primitive_word(void);
void primitive_word_hashcode(void); void primitive_word_hashcode(void);
void primitive_word_primitive(void); void primitive_word_primitive(void);
void primitive_set_word_primitive(void); void primitive_set_word_primitive(void);
void primitive_word_xt(void);
void primitive_set_word_xt(void);
void primitive_word_parameter(void); void primitive_word_parameter(void);
void primitive_set_word_parameter(void); void primitive_set_word_parameter(void);
void primitive_word_plist(void); void primitive_word_plist(void);