Starting work on Win64 port

db4
unknown 2008-11-07 20:33:32 -06:00
parent e45df2e89c
commit 7365959f01
23 changed files with 175 additions and 74 deletions

View File

@ -170,7 +170,7 @@ vm/resources.o:
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -c $(CFLAGS) -o $@ $<
.S.o: .S.o:
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -x assembler-with-cpp -c $(CFLAGS) -o $@ $<
.m.o: .m.o:
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -c $(CFLAGS) -o $@ $<

View File

@ -435,7 +435,7 @@ M: long-long-type box-return ( type -- )
[ >float ] >>unboxer-quot [ >float ] >>unboxer-quot
"double" define-primitive-type "double" define-primitive-type
os winnt? cpu x86.64? and "longlong" "long" ? "ptrdiff_t" typedef "long" "ptrdiff_t" typedef
"ulong" "size_t" typedef "ulong" "size_t" typedef
] with-compilation-unit ] with-compilation-unit

View File

@ -25,7 +25,7 @@ IN: bootstrap.image
: images ( -- seq ) : images ( -- seq )
{ {
"x86.32" "x86.32"
"x86.64" "winnt-x86.64" "unix-x86.64"
"linux-ppc" "macosx-ppc" "linux-ppc" "macosx-ppc"
} ; } ;

View File

@ -26,6 +26,8 @@ M: x86.32 stack-reg ESP ;
M: x86.32 temp-reg-1 EAX ; M: x86.32 temp-reg-1 EAX ;
M: x86.32 temp-reg-2 ECX ; M: x86.32 temp-reg-2 ECX ;
M: x86.32 reserved-area-size 0 ;
M: x86.32 %alien-global 0 [] MOV rc-absolute-cell rel-dlsym ; M: x86.32 %alien-global 0 [] MOV rc-absolute-cell rel-dlsym ;
M: x86.32 %alien-invoke (CALL) rel-dlsym ; M: x86.32 %alien-invoke (CALL) rel-dlsym ;

View File

@ -6,6 +6,7 @@ IN: bootstrap.x86
4 \ cell set 4 \ cell set
: stack-frame-size ( -- n ) 4 bootstrap-cells ;
: shift-arg ( -- reg ) ECX ; : shift-arg ( -- reg ) ECX ;
: div-arg ( -- reg ) EAX ; : div-arg ( -- reg ) EAX ;
: mod-arg ( -- reg ) EDX ; : mod-arg ( -- reg ) EDX ;

View File

@ -24,14 +24,12 @@ M: x86.64 stack-reg RSP ;
M: x86.64 temp-reg-1 RAX ; M: x86.64 temp-reg-1 RAX ;
M: x86.64 temp-reg-2 RCX ; M: x86.64 temp-reg-2 RCX ;
: param-reg-1 int-regs param-regs first ; inline
: param-reg-2 int-regs param-regs second ; inline
M: int-regs return-reg drop RAX ; M: int-regs return-reg drop RAX ;
M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
M: float-regs return-reg drop XMM0 ; M: float-regs return-reg drop XMM0 ;
M: float-regs param-regs
drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
M: x86.64 rel-literal-x86 rc-relative rel-literal ; M: x86.64 rel-literal-x86 rc-relative rel-literal ;
M: x86.64 %prologue ( n -- ) M: x86.64 %prologue ( n -- )
@ -90,7 +88,7 @@ M: struct-type flatten-value-type ( type -- seq )
M: x86.64 %prepare-unbox ( -- ) M: x86.64 %prepare-unbox ( -- )
! First parameter is top of stack ! First parameter is top of stack
RDI R14 [] MOV param-reg-1 R14 [] MOV
R14 cell SUB ; R14 cell SUB ;
M: x86.64 %unbox ( n reg-class func -- ) M: x86.64 %unbox ( n reg-class func -- )
@ -103,27 +101,27 @@ M: x86.64 %unbox-long-long ( n func -- )
int-regs swap %unbox ; int-regs swap %unbox ;
: %unbox-struct-field ( c-type i -- ) : %unbox-struct-field ( c-type i -- )
! Alien must be in RDI. ! Alien must be in param-reg-1.
RDI swap cells [+] swap reg-class>> { param-reg-1 swap cells [+] swap reg-class>> {
{ int-regs [ int-regs get pop swap MOV ] } { int-regs [ int-regs get pop swap MOV ] }
{ double-float-regs [ float-regs get pop swap MOVSD ] } { double-float-regs [ float-regs get pop swap MOVSD ] }
} case ; } case ;
M: x86.64 %unbox-small-struct ( c-type -- ) M: x86.64 %unbox-small-struct ( c-type -- )
! Alien must be in RDI. ! Alien must be in param-reg-1.
"alien_offset" f %alien-invoke "alien_offset" f %alien-invoke
! Move alien_offset() return value to RDI so that we don't ! Move alien_offset() return value to param-reg-1 so that we don't
! clobber it. ! clobber it.
RDI RAX MOV param-reg-1 RAX MOV
[ [
flatten-small-struct [ %unbox-struct-field ] each-index flatten-small-struct [ %unbox-struct-field ] each-index
] with-return-regs ; ] with-return-regs ;
M: x86.64 %unbox-large-struct ( n c-type -- ) M: x86.64 %unbox-large-struct ( n c-type -- )
! Source is in RDI ! Source is in param-reg-1
heap-size heap-size
! Load destination address ! Load destination address
RSI rot stack@ LEA param-reg-2 rot stack@ LEA
! Load structure size ! Load structure size
RDX swap MOV RDX swap MOV
! Copy the struct to the C stack ! Copy the struct to the C stack
@ -160,8 +158,8 @@ M: x86.64 %box-small-struct ( c-type -- )
[ [
[ flatten-small-struct [ %box-struct-field ] each-index ] [ flatten-small-struct [ %box-struct-field ] each-index ]
[ RDX swap heap-size MOV ] bi [ RDX swap heap-size MOV ] bi
RDI 0 box-struct-field@ MOV param-reg-1 0 box-struct-field@ MOV
RSI 1 box-struct-field@ MOV param-reg-2 1 box-struct-field@ MOV
"box_small_struct" f %alien-invoke "box_small_struct" f %alien-invoke
] with-return-regs ; ] with-return-regs ;
@ -170,9 +168,9 @@ M: x86.64 %box-small-struct ( c-type -- )
M: x86.64 %box-large-struct ( n c-type -- ) M: x86.64 %box-large-struct ( n c-type -- )
! Struct size is parameter 2 ! Struct size is parameter 2
RSI swap heap-size MOV param-reg-2 swap heap-size MOV
! Compute destination address ! Compute destination address
RDI swap struct-return@ LEA param-reg-1 swap struct-return@ LEA
! Copy the struct from the C stack ! Copy the struct from the C stack
"box_value_struct" f %alien-invoke ; "box_value_struct" f %alien-invoke ;
@ -200,7 +198,7 @@ M: x86.64 %alien-indirect ( -- )
RBP CALL ; RBP CALL ;
M: x86.64 %alien-callback ( quot -- ) M: x86.64 %alien-callback ( quot -- )
RDI swap %load-indirect param-reg-1 swap %load-indirect
"c_to_factor" f %alien-invoke ; "c_to_factor" f %alien-invoke ;
M: x86.64 %callback-value ( ctype -- ) M: x86.64 %callback-value ( ctype -- )
@ -208,11 +206,11 @@ M: x86.64 %callback-value ( ctype -- )
%prepare-unbox %prepare-unbox
! Save top of data stack ! Save top of data stack
RSP 8 SUB RSP 8 SUB
RDI PUSH param-reg-1 PUSH
! Restore data/call/retain stacks ! Restore data/call/retain stacks
"unnest_stacks" f %alien-invoke "unnest_stacks" f %alien-invoke
! Put former top of data stack in RDI ! Put former top of data stack in param-reg-1
RDI POP param-reg-1 POP
RSP 8 ADD RSP 8 ADD
! Unbox former top of data stack to return registers ! Unbox former top of data stack to return registers
unbox-return ; unbox-return ;
@ -223,3 +221,10 @@ enable-alien-4-intrinsics
! SSE2 is always available on x86-64. ! SSE2 is always available on x86-64.
enable-float-intrinsics enable-float-intrinsics
USE: vocabs.loader
{
{ [ os unix? ] [ "cpu.x86.64.unix" require ] }
{ [ os winnt? ] [ "cpu.x86.64.winnt" require ] }
} cond

View File

@ -9,8 +9,6 @@ IN: bootstrap.x86
: shift-arg ( -- reg ) RCX ; : shift-arg ( -- reg ) RCX ;
: div-arg ( -- reg ) RAX ; : div-arg ( -- reg ) RAX ;
: mod-arg ( -- reg ) RDX ; : mod-arg ( -- reg ) RDX ;
: arg0 ( -- reg ) RDI ;
: arg1 ( -- reg ) RSI ;
: temp-reg ( -- reg ) RBX ; : temp-reg ( -- reg ) RBX ;
: stack-reg ( -- reg ) RSP ; : stack-reg ( -- reg ) RSP ;
: ds-reg ( -- reg ) R14 ; : ds-reg ( -- reg ) R14 ;

View File

@ -0,0 +1,12 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
cpu.x86.assembler layouts vocabs parser ;
IN: bootstrap.x86
: stack-frame-size ( -- n ) 4 bootstrap-cells ;
: arg0 ( -- reg ) RDI ;
: arg1 ( -- reg ) RSI ;
<< "resource:basis/cpu/x86/64/bootstrap.factor" parsed-file parsed >>
call

View File

@ -0,0 +1,12 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel layouts system compiler.cfg.registers
cpu.architecture cpu.x86.assembler ;
IN: cpu.x86.64.unix
M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
M: float-regs param-regs
drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
M: x86.64 reserved-area-size 0 ;

View File

@ -0,0 +1,12 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel namespaces system
cpu.x86.assembler layouts vocabs parser ;
IN: bootstrap.x86
: stack-frame-size ( -- n ) 8 bootstrap-cells ;
: arg0 ( -- reg ) RCX ;
: arg1 ( -- reg ) RDX ;
<< "resource:basis/cpu/x86/64/bootstrap.factor" parse-file parsed >>
call

View File

@ -0,0 +1,17 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel layouts system alien.c-types compiler.cfg.registers
cpu.architecture cpu.x86.assembler cpu.x86 ;
IN: cpu.x86.64.winnt
M: int-regs param-regs drop { RCX RDX R8 R9 } ;
M: float-regs param-regs drop { XMM0 XMM1 XMM2 XMM3 } ;
M: x86.64 reserved-area-size 4 cells ;
<<
"longlong" "ptrdiff_t" typedef
"int" "long" typedef
"uint" "ulong" typedef
>>

View File

@ -10,8 +10,6 @@ big-endian off
1 jit-code-format set 1 jit-code-format set
: stack-frame-size ( -- n ) 4 bootstrap-cells ;
[ [
! Load word ! Load word
temp-reg 0 MOV temp-reg 0 MOV
@ -30,7 +28,7 @@ big-endian off
temp-reg 0 MOV ! load XT temp-reg 0 MOV ! load XT
stack-frame-size PUSH ! save stack frame size stack-frame-size PUSH ! save stack frame size
temp-reg PUSH ! push XT temp-reg PUSH ! push XT
arg1 PUSH ! alignment stack-reg stack-frame-size 3 bootstrap-cells - SUB ! alignment
] rc-absolute-cell rt-label 1 rex-length + jit-prolog jit-define ] rc-absolute-cell rt-label 1 rex-length + jit-prolog jit-define
[ [
@ -302,14 +300,14 @@ big-endian off
shift-arg ds-reg [] MOV ! load shift count shift-arg ds-reg [] MOV ! load shift count
shift-arg tag-bits get SAR ! untag shift count shift-arg tag-bits get SAR ! untag shift count
ds-reg bootstrap-cell SUB ! adjust stack pointer ds-reg bootstrap-cell SUB ! adjust stack pointer
arg0 ds-reg [] MOV ! load value temp-reg ds-reg [] MOV ! load value
arg1 arg0 MOV ! make a copy arg1 temp-reg MOV ! make a copy
arg1 CL SHL ! compute positive shift value in arg1 arg1 CL SHL ! compute positive shift value in arg1
shift-arg NEG ! compute negative shift value in arg0 shift-arg NEG ! compute negative shift value in arg0
arg0 CL SAR temp-reg CL SAR
arg0 tag-mask get bitnot AND temp-reg tag-mask get bitnot AND
shift-arg 0 CMP ! if shift count was negative, move arg0 to arg1 shift-arg 0 CMP ! if shift count was negative, move arg0 to arg1
arg1 arg0 CMOVGE arg1 temp-reg CMOVGE
ds-reg [] arg1 MOV ! push to stack ds-reg [] arg1 MOV ! push to stack
] f f f \ fixnum-shift-fast define-sub-primitive ] f f f \ fixnum-shift-fast define-sub-primitive

View File

@ -39,12 +39,15 @@ M: x86 %inc-r ( n -- ) rs-reg (%inc) ;
: align-stack ( n -- n' ) : align-stack ( n -- n' )
os macosx? cpu x86.64? or [ 16 align ] when ; os macosx? cpu x86.64? or [ 16 align ] when ;
HOOK: reserved-area-size cpu ( -- n )
M: x86 stack-frame-size ( stack-frame -- i ) M: x86 stack-frame-size ( stack-frame -- i )
[ spill-counts>> [ swap reg-size * ] { } assoc>map sum ] [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ]
[ params>> ] [ params>> ]
[ return>> ] [ return>> ]
tri + + tri + +
3 cells + 3 cells +
reserved-area-size +
align-stack ; align-stack ;
M: x86 %call ( label -- ) CALL ; M: x86 %call ( label -- ) CALL ;
@ -465,7 +468,7 @@ M: x86 %compare-float-branch ( label cc src1 src2 -- )
: stack@ ( n -- op ) stack-reg swap [+] ; : stack@ ( n -- op ) stack-reg swap [+] ;
: spill-integer-base ( stack-frame -- n ) : spill-integer-base ( stack-frame -- n )
[ params>> ] [ return>> ] bi + ; [ params>> ] [ return>> ] bi + reserved-area-size + ;
: spill-integer@ ( n -- op ) : spill-integer@ ( n -- op )
cells cells
@ -473,10 +476,9 @@ M: x86 %compare-float-branch ( label cc src1 src2 -- )
+ stack@ ; + stack@ ;
: spill-float-base ( stack-frame -- n ) : spill-float-base ( stack-frame -- n )
[ spill-integer-base ]
[ spill-counts>> int-regs swap at int-regs reg-size * ] [ spill-counts>> int-regs swap at int-regs reg-size * ]
[ params>> ] bi + ;
[ return>> ]
tri + + ;
: spill-float@ ( n -- op ) : spill-float@ ( n -- op )
double-float-regs reg-size * double-float-regs reg-size *

View File

@ -1,5 +1,5 @@
#WIN64_PATH=/k/MinGW/win64/bin #WIN64_PATH=/k/MinGW/win64/bin
WIN64_PATH=/cygdrive/k/MinGW/win64/bin/x86_64-pc-mingw32 #WIN64_PATH=/cygdrive/k/MinGW/win64/bin/x86_64-pc-mingw32
CC=$(WIN64_PATH)-gcc.exe CC=$(WIN64_PATH)-gcc.exe
WINDRES=$(WIN64_PATH)-windres.exe WINDRES=$(WIN64_PATH)-windres.exe
include vm/Config.windows.nt include vm/Config.windows.nt

View File

@ -116,6 +116,8 @@ CELL frame_executing(F_STACK_FRAME *frame)
F_STACK_FRAME *frame_successor(F_STACK_FRAME *frame) F_STACK_FRAME *frame_successor(F_STACK_FRAME *frame)
{ {
if(frame->size == 0)
critical_error("Stack frame has zero size",frame);
return (F_STACK_FRAME *)((CELL)frame - frame->size); return (F_STACK_FRAME *)((CELL)frame - frame->size);
} }

View File

@ -11,6 +11,7 @@ and the callstack top is passed in EDX */
#define RETURN_REG %eax #define RETURN_REG %eax
#define CELL_SIZE 4 #define CELL_SIZE 4
#define STACK_PADDING 12
#define PUSH_NONVOLATILE \ #define PUSH_NONVOLATILE \
push %ebx ; \ push %ebx ; \

View File

@ -1,34 +1,65 @@
#include "asm.h" #include "asm.h"
#define ARG0 %rdi
#define ARG1 %rsi
#define STACK_REG %rsp #define STACK_REG %rsp
#define DS_REG %r14 #define DS_REG %r14
#define RETURN_REG %rax #define RETURN_REG %rax
#define CELL_SIZE 8 #define CELL_SIZE 8
#define STACK_PADDING 56
#define PUSH_NONVOLATILE \ #ifdef WINDOWS
#define ARG0 %rcx
#define ARG1 %rdx
#define ARG2 %r8
#define ARG3 %r9
#define PUSH_NONVOLATILE \
push %r12 ; \
push %r13 ; \
push %rdi ; \
push %rsi ; \
push %rbx ; \
push %rbp
#define POP_NONVOLATILE \
pop %rbp ; \
pop %rbx ; \
pop %rsi ; \
pop %rdi ; \
pop %r13 ; \
pop %r12
#else
#define ARG0 %rdi
#define ARG1 %rsi
#define ARG2 %rdx
#define ARG3 %rcx
#define PUSH_NONVOLATILE \
push %rbx ; \ push %rbx ; \
push %rbp ; \ push %rbp ; \
push %r12 ; \ push %r12 ; \
push %r13 ; push %r13
#define POP_NONVOLATILE \ #define POP_NONVOLATILE \
pop %r13 ; \ pop %r13 ; \
pop %r12 ; \ pop %r12 ; \
pop %rbp ; \ pop %rbp ; \
pop %rbx pop %rbx
#endif
#define QUOT_XT_OFFSET 21 #define QUOT_XT_OFFSET 21
/* We pass a function pointer to memcpy to work around a Mac OS X /* We pass a function pointer to memcpy to work around a Mac OS X
ABI limitation which would otherwise require us to do a bizzaro PC-relative ABI limitation which would otherwise require us to do a bizzaro PC-relative
trampoline to retrieve the function address */ trampoline to retrieve the function address */
DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy)): DEF(void,set_callstack,(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy)):
sub %rdx,%rdi /* compute new stack pointer */ sub ARG2,ARG0 /* compute new stack pointer */
mov %rdi,%rsp mov ARG0,%rsp
call *%rcx /* call memcpy */ call *ARG3 /* call memcpy */
ret /* return _with new stack_ */ ret /* return _with new stack_ */
#include "cpu-x86.S" #include "cpu-x86.S"

View File

@ -1,31 +1,34 @@
DEF(F_FASTCALL void,c_to_factor,(CELL quot)): DEF(F_FASTCALL void,c_to_factor,(CELL quot)):
PUSH_NONVOLATILE PUSH_NONVOLATILE
push ARG0 /* Save quot */ push ARG0
lea -CELL_SIZE(STACK_REG),ARG0 /* Save stack pointer */ /* Save stack pointer */
lea -CELL_SIZE(STACK_REG),ARG0
/* Create register shadow area for Win64 */
sub $32,STACK_REG
call MANGLE(save_callstack_bottom) call MANGLE(save_callstack_bottom)
add $32,STACK_REG
mov (STACK_REG),ARG0 /* Pass quot as arg 1 */ /* Call quot-xt */
call *QUOT_XT_OFFSET(ARG0) /* Call quot-xt */ mov (STACK_REG),ARG0
call *QUOT_XT_OFFSET(ARG0)
POP ARG0 pop ARG0
POP_NONVOLATILE POP_NONVOLATILE
ret ret
DEF(F_FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): DEF(F_FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)):
mov ARG1,STACK_REG /* rewind_to */ /* rewind_to */
mov ARG1,STACK_REG
jmp *QUOT_XT_OFFSET(ARG0) jmp *QUOT_XT_OFFSET(ARG0)
DEF(FASTCALL void,lazy_jit_compile,(CELL quot)): DEF(FASTCALL void,lazy_jit_compile,(CELL quot)):
mov STACK_REG,ARG1 /* Save stack pointer */ mov STACK_REG,ARG1 /* Save stack pointer */
push ARG1 /* Alignment */ sub $STACK_PADDING,STACK_REG
push ARG1
push ARG1
call MANGLE(primitive_jit_compile) call MANGLE(primitive_jit_compile)
mov RETURN_REG,ARG0 /* No-op on 32-bit */ mov RETURN_REG,ARG0 /* No-op on 32-bit */
pop ARG1 /* OK to clobber ARG1 here */ add $STACK_PADDING,STACK_REG
pop ARG1
pop ARG1
jmp *QUOT_XT_OFFSET(ARG0) /* Call the quotation */ jmp *QUOT_XT_OFFSET(ARG0) /* Call the quotation */
#ifdef WINDOWS #ifdef WINDOWS

View File

@ -438,6 +438,8 @@ void collect_gen_cards(CELL gen)
old->new references */ old->new references */
void collect_cards(void) void collect_cards(void)
{ {
GC_PRINT("Collect cards\n");
int i; int i;
for(i = collecting_gen + 1; i < data_heap->gen_count; i++) for(i = collecting_gen + 1; i < data_heap->gen_count; i++)
collect_gen_cards(i); collect_gen_cards(i);
@ -465,7 +467,10 @@ void collect_callstack(F_CONTEXT *stacks)
{ {
CELL top = (CELL)stacks->callstack_top; CELL top = (CELL)stacks->callstack_top;
CELL bottom = (CELL)stacks->callstack_bottom; CELL bottom = (CELL)stacks->callstack_bottom;
GC_PRINT("Collect callstack %ld %ld\n",top,bottom);
iterate_callstack(top,bottom,collect_stack_frame); iterate_callstack(top,bottom,collect_stack_frame);
GC_PRINT("Done\n");
} }
} }
@ -481,6 +486,7 @@ void collect_gc_locals(void)
the user environment and extra roots registered with REGISTER_ROOT */ the user environment and extra roots registered with REGISTER_ROOT */
void collect_roots(void) void collect_roots(void)
{ {
GC_PRINT("Collect roots\n");
copy_handle(&T); copy_handle(&T);
copy_handle(&bignum_zero); copy_handle(&bignum_zero);
copy_handle(&bignum_pos_one); copy_handle(&bignum_pos_one);

View File

@ -167,7 +167,6 @@ void init_factor_from_args(F_CHAR *image, int argc, F_CHAR **argv, bool embedded
} }
init_factor(&p); init_factor(&p);
nest_stacks(); nest_stacks();
F_ARRAY *args = allot_array(ARRAY_TYPE,argc,F); F_ARRAY *args = allot_array(ARRAY_TYPE,argc,F);

View File

@ -363,13 +363,13 @@ CELL unbox_array_size(void)
case BIGNUM_TYPE: case BIGNUM_TYPE:
{ {
bignum_type zero = untag_object(bignum_zero); bignum_type zero = untag_object(bignum_zero);
bignum_type max = ulong_to_bignum(ARRAY_SIZE_MAX); bignum_type max = cell_to_bignum(ARRAY_SIZE_MAX);
bignum_type n = untag_object(dpeek()); bignum_type n = untag_object(dpeek());
if(bignum_compare(n,zero) != bignum_comparison_less if(bignum_compare(n,zero) != bignum_comparison_less
&& bignum_compare(n,max) == bignum_comparison_less) && bignum_compare(n,max) == bignum_comparison_less)
{ {
dpop(); dpop();
return bignum_to_ulong(n); return bignum_to_cell(n);
} }
break; break;
} }