Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] View of /sml/trunk/src/runtime/mach-dep/X86.prim.masm
ViewVC logotype

View of /sml/trunk/src/runtime/mach-dep/X86.prim.masm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (download) (annotate)
Sat Oct 4 23:33:46 1997 UTC (22 years, 9 months ago)
Original Path: sml/branches/SMLNJ/src/runtime/mach-dep/X86.prim.masm
File size: 29067 byte(s)
This commit was manufactured by cvs2svn to create branch 'SMLNJ'.
/* X86.prim.masm (MS assembler)
 *
 * COPYRIGHT (c) 1996 Bell Laboratories, Lucent Technologies
 *
 * derived from X86.prim.asm
 * derived from I386.prim.s, by Mark Leone (mleone@cs.cmu.edu)
 */

#include "ml-base.h"
#include "asm-base.h"
#include "ml-values.h"
#include "tags.h"
#include "ml-request.h"
#include "reg-mask.h"
#include "ml-limits.h"

/* enable/disable virtual (memory-based) registers.
 * the number of vregs, etc. must concur with:
 *	src/runtime/include/ml-state.h
 *	src/runtime/kernel/ml-state.c
 *      src/sml-nj/x86/x86.sml
 */

#ifndef VREGS
#  define VREGS
#endif

/*
 *
 * The 386 registers are used as follows:
 *
 * EAX - temp1 (see the code generator, x86/x86.sml)
 * EBX - misc1
 * ECX - misc2
 * EDX - misc3
 * ESI - standard continuation (ml_cont, see ml_state.h)
 * EBP - standard argument (ml_arg)
 * EDI - free space pointer (ml_allocptr)
 * ESP - stack pointer
 * EIP - program counter (ml_pc)
 */

/* Registers (see x86/x86.sml): */
#define temp		REG(eax)
#define misc1		REG(ebx)
#define misc2		REG(ecx)
#define misc3		REG(edx)
#define stdcont		REG(esi)
#define stdarg		REG(ebp)
#define allocptr	REG(edi)

/* other reg uses */
#define creturn 	REG(eax)

/*
 * Other values, which on most architectures would reside in registers,
 * are stored on the stack:
 * 
 * 0(ESP) - tempmem (used by the X86 code generator)
 * 4(ESP) - tempmem2 (used by the X86 code generator)
 * 8(ESP) - exception handler continuation (ml_exncont)
 * 12(ESP) - data limit (ml_limitptr)
 * 16(ESP) - standard closure (ml_closure)
 * 20(ESP) - link register (ml_linkreg)
 * 24(ESP) - store pointer (ml_storeptr)
 * 28(ESP) - var pointer (ml_varptr)
 *
 */

/* Stack frame (see x86/x86.sml): */
#define tempmem		IND_DW_OFF(REG(esp),0)
#define tempmem2	IND_DW_OFF(REG(esp),4)
#define exncont		IND_DW_OFF(REG(esp),8)
#define limitptr	IND_DW_OFF(REG(esp),12)
#define stdclos		IND_DW_OFF(REG(esp),16)
#define stdlink		IND_DW_OFF(REG(esp),20)
#define storeptr	IND_DW_OFF(REG(esp),24)
#define varptr		IND_DW_OFF(REG(esp),28)
#define start_gc	IND_DW_OFF(REG(esp),32)
#define mask		IND_DW_OFF(REG(esp),36)
#define vreg0		IND_DW_OFF(REG(esp),40)
#define vreg1		IND_DW_OFF(REG(esp),44)
#define vreg2		IND_DW_OFF(REG(esp),48)
#define vreg3		IND_DW_OFF(REG(esp),52)
#define vreg4		IND_DW_OFF(REG(esp),56)
#define vreg5		IND_DW_OFF(REG(esp),60)
#define vreg6		IND_DW_OFF(REG(esp),64)
#define vreg7		IND_DW_OFF(REG(esp),68)
#define vreg8		IND_DW_OFF(REG(esp),72)
#define vreg9		IND_DW_OFF(REG(esp),76)
#define vreg10		IND_DW_OFF(REG(esp),80)
#define vreg11		IND_DW_OFF(REG(esp),84)
#define vreg12		IND_DW_OFF(REG(esp),88)     /* used as pseudo reg */
#define vreg13		IND_DW_OFF(REG(esp),92)     /* used as pseudo reg */
#define vreg14		IND_DW_OFF(REG(esp),96)     /* unused */
#define vreg15		IND_DW_OFF(REG(esp),100)    /* unused */
#define mlstate_ptr	IND_DW_OFF(REG(esp),104)
#define ML_STATE_OFFSET 104
#define ML_FRAME_SIZE	(ML_STATE_OFFSET+4)


#define PSEUDOREG_1	vreg12
#define PSEUDOREG_2 	vreg13

#define	via

.386
.MODEL FLAT

	DATA
	ALIGN4
WORD32(tempmem_w,0)	/* temp word for the code generator */
WORD32(tempmem2_w,0)	/* another temp word for the code generator */
WORD32(request_w,0)	/* place to put the request code */

	GLOBAL(CSYM(ML_X86Frame))
WORD32(CSYM(ML_X86Frame),0) /* ptr to the ml frame (gives C access to limitptr) */

/*
 * Note that the garbage collector only preserves root registers 
 * (EBX, ECX, EDX, ESI, EBP, EIP).
 */


#include "mlstate-offsets.h"	/** this file is generated **/


/*
 * 386 function call conventions:  
 *  [true for gcc and dynix3 cc; untested for others]
 *
 * 	Caller save registers: eax, ecx, edx
 * 	Callee save registers: ebx, esi, edi, and ebp. 
 * 	Floating point state is caller-save.
 * 	Arguments passed on stack.  Rightmost argument pushed first.
 * 	Word-sized result returned in %eax.
 */

#define cresult	REG(eax)

CALLEE_SAVE_M MACRO
	PUSHL	REG(ebx)
	PUSHL	REG(esi)
	PUSHL	REG(edi)
	PUSHL	REG(ebp)	
ENDM
#define CALLEE_SAVE CALLEE_SAVE_M

CALLEE_RESTORE_M MACRO
	POPL	REG(ebp)
	POPL	REG(edi)
	POPL	REG(esi)
	POPL	REG(ebx)
ENDM 
#define CALLEE_RESTORE CALLEE_RESTORE_M

/* MOVE copies one memory location to another, using a specified temporary. */

EXCHANGE_M MACRO src,tmp,dest
	MOVL	(src, tmp)
	MOVL	(tmp, dest)
ENDM
#define MOVE(a,b,c) EXCHANGE_M a, b, c

CONTINUE_M MACRO
#if (CALLEESAVE > 0)
	CMPL	(limitptr, allocptr)
	JMP     via stdcont
#else
	MOVL	(IND_DW_OFF(stdcont,0), temp)
	MOVL	(temp, stdlink)	  	/* Not really a register */
	CMPL	(limitptr, allocptr)
	JMP     via temp
#endif
ENDM
#define CONTINUE CONTINUE_M

CHECKLIMIT_M MACRO maskval
 ANON_LAB:
	jb	FLAB_ANON
	LEA	(BLAB_ANON, temp)	/* temp holds resume address */
	MOVL	(IMMED(maskval), mask)
	JMP	via CSYM(saveregs)
 ANON_LAB:
ENDM
#define CHECKLIMIT(mask) CHECKLIMIT_M mask

ENTRY_M MACRO id
	GLOBAL(CSYM(&id))
	LABEL(CSYM(&id))
ENDM
#define ENTRY(id) ENTRY_M id

ML_CODE_HDR_M MACRO name
	GLOBAL(CSYM(&name))
	ALIGN4
	LABEL(CSYM(&name))
ENDM
#define ML_CODE_HDR(name) ML_CODE_HDR_M name


/**********************************************************************/
	TEXT
	ALIGN4

ML_CODE_HDR(sigh_return_a)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_SIG_RETURN), request_w)
	MOVL	(IMMED(RET_MASK), mask)
	JMP	CSYM(set_request)

/* sigh_resume:
 * Resume execution at the point at which a handler trap occurred.  This is a
 * standard two-argument function, thus the closure is in ml_cont.
 */

ENTRY(sigh_resume)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_SIG_RESUME), request_w)
/*	MOVL	(IMMED(RET_MASK), mask)
 */
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)

/* pollh_return_a:
 * The return continuation for the ML poll handler.
 */
ML_CODE_HDR(pollh_return_a)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_POLL_RETURN), request_w)
	MOVL	(IMMED(RET_MASK), mask)
	JMP	CSYM(set_request)

/* pollh_resume:
 * Resume execution at the point at which a poll event occurred.
 */
ENTRY(pollh_resume)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_POLL_RESUME), request_w)
/*	MOVL	(IMMED(RET_MASK), mask)
 */
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)

ML_CODE_HDR(handle_a)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_EXN), request_w)
	MOVL	(IMMED(EXN_MASK), mask)
	JMP	CSYM(set_request)

ML_CODE_HDR(return_a)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_RETURN), request_w)
	MOVL	(IMMED(RET_MASK), mask)
	JMP	CSYM(set_request)

/* Request a fault.  The floating point coprocessor must be reset
 * (thus trashing the FP registers) since we don't know whether a 
 * value has been pushed into the temporary "register".	 This is OK 
 * because no floating point registers will be live at the start of 
 * the exception handler.
 */
ENTRY(request_fault)
	CALL	CSYM(FPEEnable)		/* Doesn't trash any general regs. */
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_FAULT), request_w)
	MOVL	(IMMED(EXN_MASK), mask)
	JMP	CSYM(set_request)

/* bind_cfun : (string * string) -> c_function
 */
ML_CODE_HDR(bind_cfun_a)
	CHECKLIMIT(FUN_MASK)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_BIND_CFUN), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)

ML_CODE_HDR(build_literals_a)
	CHECKLIMIT(FUN_MASK)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_BUILD_LITERALS), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)

ML_CODE_HDR(callc_a)
	CHECKLIMIT(FUN_MASK)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_CALLC), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	/* fall into set_request */

ENTRY(set_request)
	/* temp holds mlstate_ptr, valid request in request_w  */
	/* Save registers */
	MOVL	(allocptr,IND_DW_OFF(temp,AllocPtrOffMSP))
	MOVL	(stdarg,IND_DW_OFF(temp,StdArgOffMSP))
	MOVL	(stdcont,IND_DW_OFF(temp,StdContOffMSP))

#define	temp2 allocptr
	/* note that we have left ML code */
	MOVL	(IND_DW_OFF(temp,VProcOffMSP),temp2)
	MOVL	(IMMED(0), IND_DW_OFF(temp2,InMLOffVSP))	

#if (CALLEESAVE > 0)
	MOVL	(misc1, IND_DW_OFF(temp,MiscRegOffMSP(0)))
#if (CALLEESAVE > 1)
	MOVL	(misc2, IND_DW_OFF(temp,MiscRegOffMSP(1)))
#if (CALLEESAVE > 2)
	MOVL	(misc3, IND_DW_OFF(temp,MiscRegOffMSP(2)))

	/* Save vregs before the stack frame is popped. */

#if (CALLEESAVE > 3)
 	MOVE(vreg0, temp2, IND_DW_OFF(temp,MiscRegOffMSP(3)))
#if (CALLEESAVE > 4)
 	MOVE(vreg1, temp2, IND_DW_OFF(temp,MiscRegOffMSP(4)))
#if (CALLEESAVE > 5)
 	MOVE(vreg2, temp2, IND_DW_OFF(temp,MiscRegOffMSP(5)))
#if (CALLEESAVE > 6)
 	MOVE(vreg3, temp2, IND_DW_OFF(temp,MiscRegOffMSP(6)))
#if (CALLEESAVE > 7)
 	MOVE(vreg4, temp2, IND_DW_OFF(temp,MiscRegOffMSP(7)))
#if (CALLEESAVE > 8)
 	MOVE(vreg5, temp2, IND_DW_OFF(temp,MiscRegOffMSP(8)))
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif

	MOVE(tempmem, temp2, tempmem_w)
	MOVE(tempmem2,temp2, tempmem2_w)
	MOVE(limitptr,temp2, IND_DW_OFF(temp,LimitPtrOffMSP))
	MOVE(exncont, temp2, IND_DW_OFF(temp,ExnPtrOffMSP)) 
	MOVE(stdclos, temp2, IND_DW_OFF(temp,StdClosOffMSP))
	MOVE(stdlink, temp2, IND_DW_OFF(temp,LinkRegOffMSP))
	MOVE(stdlink, temp2, IND_DW_OFF(temp,PCOffMSP))
	MOVE(storeptr,temp2, IND_DW_OFF(temp,StorePtrOffMSP))
	MOVE(varptr,  temp2, IND_DW_OFF(temp,VarPtrOffMSP))
	MOVE(mask,    temp2, IND_DW_OFF(temp,MaskOffMSP))

	/* pseudo regs */
	MOVE(PSEUDOREG_1,temp2,IND_DW_OFF(temp,PseudoReg1OffMSP))
	MOVE(PSEUDOREG_2,temp2,IND_DW_OFF(temp,PseudoReg2OffMSP))
#undef	temp2	
	
	/* return val of function is request code */
	MOVL	(request_w,creturn)

	/* Pop the stack frame and return to run_ml(). */
	ADDL	(IMMED(ML_FRAME_SIZE), REG(esp))
	CALLEE_RESTORE
	RET

	TEXT
	ALIGN4

ENTRY(saveregs)
	PUSHL	temp			/* Contains "resume" address. */
	MOVL	(IND_DW_OFF(REG(esp),ML_STATE_OFFSET+4), temp)
	POPL	IND_DW_OFF(temp,PCOffMSP)

#ifdef SOFT_POLL
	/* free some regs */
	MOVL	(misc1, IND_DW_OFF(temp,MiscRegOffMSP(0)))
	MOVL	(misc2, IND_DW_OFF(temp,MiscRegOffMSP(1)))
#define tmpR	misc1
#define pfreq	misc2
	/* check if polling enabled (PollFreq > 0) */
	LEA	(CSYM(_PollFreq0),pfreq)	/* load contents of ref */
	MOVL	(IND_DW_OFF(pfreq,4),pfreq)			
	SHRL	(IMMED(1),pfreq)		/* strip integer tag */
	JZ	check_for_gc			/* go check for real gc */
	CMPL	(IMMED(0),IND_DW_OFF(temp,InPollHandlerOffMSP))  /* if we're in the handler */
	JNE	reset_limit			/* ignore poll events */
	LEA	(CSYM(_PollEvent0),tmpR)	/* load contents of ref */
	MOVL	(IND_DW_OFF(tmpR,4),tmpR)
	SHRL	(IMMED(1),tmpR)
	JZ	reset_limit			/* check for poll event */
	/* event occurred, so set ml_pollHandlerPending */
	MOVL	(IMMED(1),IND_DW_OFF(temp,PollPendingOffMSP))
	JMP	do_gc		/* and handle event in the C runtime */
	
reset_limit:	/* reset limit ptr */
	SHLL	(IMMED(POLL_GRAIN_BITS),pfreq)	/* mult by POLL_GRAIN_CPSI */
	MOVL	(allocptr,limitptr)
	ADDL	(pfreq,limitptr)
#undef	pfreq

check_for_gc:
	/* ensure real limit is >= limit */
	MOVL	(IND_DW_OFF(temp,RealLimitOffMSP),tmpR)
	CMPL	(limitptr,tmpR)
	JA	ok_limit
	MOVL	(tmpR,limitptr)
ok_limit:
	ADDL	(IMMED(-4096),limitptr)
	CMPL	(limitptr,allocptr)
	JGE	do_gc		       	/* gc *//* should be a common case */
	ADDL	(IMMED(4096),limitptr)
	/* since a signal also sets limitptr == allocptr to force a trap, */
	/* we need to disambiguate poll-events/signals here */
#define	vsp	misc2
	MOVL	($0,tmpR)
	ADDL	(IND_DW_OFF(temp,PollPendingOffMSP),tmpR)
	MOVL	(IND_DW_OFF(temp,VProcOffMSP),vsp)
	ADDL	(IND_DW_OFF(vsp,NPendingOffVSP),tmpR)
	ADDL	(IND_DW_OFF(vsp,NPendingSysOffVSP),tmpR)
	JNZ	do_gc
#undef  vsp

no_gc:	/* an uneventful poll check, back to ML */
	MOVL	(IND_DW_OFF(temp,MiscRegOffMSP(0)),misc1)
	MOVL	(IND_DW_OFF(temp,MiscRegOffMSP(1)),misc2)
	MOVL	(IND_DW_OFF(temp,PCOffMSP),temp)
	CMPL	(limitptr, allocptr)
	JMPL	temp

do_gc:
	/* limitptr saved below */

#undef tmpR
#endif /* SOFT_POLL */


	/* Save registers. */
	MOVL	(allocptr, IND_DW_OFF(temp,AllocPtrOffMSP))
	MOVL	(stdarg, IND_DW_OFF(temp,StdArgOffMSP))
	MOVL	(stdcont, IND_DW_OFF(temp,StdContOffMSP))
#ifndef SOFT_POLL  /* misc1 & misc2 saved above for SOFT_POLL */
	MOVL	(misc1, IND_DW_OFF(temp,MiscRegOffMSP(0)))
	MOVL	(misc2, IND_DW_OFF(temp,MiscRegOffMSP(1)))
#endif
	MOVL	(misc3, IND_DW_OFF(temp,MiscRegOffMSP(2)))

#define	temp2 allocptr

	/* note that we have left ML code */
	MOVL	(IND_DW_OFF(temp,VProcOffMSP),temp2)
	MOVL	(IMMED(0), IND_DW_OFF(temp2,InMLOffVSP))

	/* vregs */
#ifdef VREGS
	MOVE(vreg0, temp2, IND_DW_OFF(temp,MiscRegOffMSP(3)))
	MOVE(vreg1, temp2, IND_DW_OFF(temp,MiscRegOffMSP(4)))
	MOVE(vreg2, temp2, IND_DW_OFF(temp,MiscRegOffMSP(5)))
	MOVE(vreg3, temp2, IND_DW_OFF(temp,MiscRegOffMSP(6)))
	MOVE(vreg4, temp2, IND_DW_OFF(temp,MiscRegOffMSP(7)))
	MOVE(vreg5, temp2, IND_DW_OFF(temp,MiscRegOffMSP(8)))
	MOVE(vreg6, temp2, IND_DW_OFF(temp,MiscRegOffMSP(9)))
	MOVE(vreg7, temp2, IND_DW_OFF(temp,MiscRegOffMSP(10)))
	MOVE(vreg8, temp2, IND_DW_OFF(temp,MiscRegOffMSP(11)))
	MOVE(vreg9, temp2, IND_DW_OFF(temp,MiscRegOffMSP(12)))
	MOVE(vreg10, temp2, IND_DW_OFF(temp,MiscRegOffMSP(13)))
	MOVE(vreg11, temp2, IND_DW_OFF(temp,MiscRegOffMSP(14)))
#endif

	MOVE(tempmem, temp2, tempmem_w)
	MOVE(tempmem2,temp2, tempmem2_w)
	MOVE(exncont, temp2, IND_DW_OFF(temp,ExnPtrOffMSP)) 
	MOVE(stdclos, temp2, IND_DW_OFF(temp,StdClosOffMSP))
	MOVE(stdlink, temp2, IND_DW_OFF(temp,LinkRegOffMSP))
	MOVE(storeptr,temp2, IND_DW_OFF(temp,StorePtrOffMSP))
	MOVE(limitptr,temp2, IND_DW_OFF(temp,LimitPtrOffMSP))
	MOVE(varptr,  temp2, IND_DW_OFF(temp,VarPtrOffMSP))
	MOVE(mask,    temp2, IND_DW_OFF(temp,MaskOffMSP))

	/* pseudo regs */
	MOVE(PSEUDOREG_1,temp2,IND_DW_OFF(temp,PseudoReg1OffMSP))
	MOVE(PSEUDOREG_2,temp2,IND_DW_OFF(temp,PseudoReg2OffMSP))
#undef	temp2	

	/* Pop the stack frame and return to run_ml(). */
	MOVL	(IMMED(REQ_GC),creturn)
	ADDL	(IMMED(ML_FRAME_SIZE), REG(esp))
	CALLEE_RESTORE
	RET

ENTRY(asm_restoreregs)
	MOVL	(IND_DW_OFF(REG(esp),4), temp)/* Get argument (MLState ptr). */
	CALLEE_SAVE

#define temp2	REG(ebx)
	/* Allocate and initialize the ML stack frame. */
	SUBL	(IMMED(ML_FRAME_SIZE), REG(esp))
	MOVE(	tempmem_w,  temp2, tempmem)
	MOVE(	tempmem2_w, temp2, tempmem2)
	MOVE(	IND_DW_OFF(temp,ExnPtrOffMSP), temp2, exncont) 
	MOVE(	IND_DW_OFF(temp,LimitPtrOffMSP), temp2, limitptr)
	MOVE(	IND_DW_OFF(temp,StdClosOffMSP), temp2, stdclos)
	MOVE(	IND_DW_OFF(temp,LinkRegOffMSP), temp2, stdlink) 
	MOVE(	IND_DW_OFF(temp,StorePtrOffMSP), temp2, storeptr)
	MOVE(	IND_DW_OFF(temp,VarPtrOffMSP), temp2, varptr)
	MOVE(	IND_DW_OFF(temp,MaskOffMSP), temp2, mask)
	LEA	(CSYM(saveregs), temp2)
	MOVL	(temp2,start_gc)
	MOVL	(temp, mlstate_ptr)

	/* vregs */
#ifdef VREGS
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(3)),temp2,vreg0) 
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(4)),temp2,vreg1) 
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(5)),temp2,vreg2) 
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(6)),temp2,vreg3) 
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(7)), temp2, vreg4)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(8)), temp2, vreg5)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(9)), temp2, vreg6)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(10)), temp2, vreg7)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(11)), temp2, vreg8)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(12)), temp2, vreg9)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(13)), temp2, vreg10)
	MOVE(IND_DW_OFF(temp,MiscRegOffMSP(14)), temp2, vreg11)
#endif
	/* pseudo regs */
	MOVE(IND_DW_OFF(temp,PseudoReg1OffMSP),temp2,PSEUDOREG_1)
	MOVE(IND_DW_OFF(temp,PseudoReg2OffMSP),temp2,PSEUDOREG_2)

#undef	temp2

	/* Load ML registers. */
	MOVL	(IND_DW_OFF(temp,AllocPtrOffMSP), allocptr)
	MOVL	(IND_DW_OFF(temp,StdContOffMSP), stdcont)
	MOVL	(IND_DW_OFF(temp,StdArgOffMSP), stdarg)
	MOVL	(IND_DW_OFF(temp,MiscRegOffMSP(0)), misc1)
	MOVL	(IND_DW_OFF(temp,MiscRegOffMSP(1)), misc2)
	MOVL	(IND_DW_OFF(temp,MiscRegOffMSP(2)), misc3)

	MOVL	(REG(esp),CSYM(ML_X86Frame))/* frame ptr for signal handler. */

	PUSHL	misc2			/* free up a register   */
	PUSHL	temp			/* save msp temporarily */

#define	tmpreg	misc2

	/* note that we're entering ML */
	MOVL	(IND_DW_OFF(temp,VProcOffMSP),temp)  /* temp is now vsp */
#define vsp	temp
	MOVL	(IMMED(1),IND_DW_OFF(vsp,InMLOffVSP))

	/* handle signals */
	MOVL	(IND_DW_OFF(vsp,NPendingSysOffVSP),tmpreg)
	ADDL	(IND_DW_OFF(vsp,NPendingOffVSP),tmpreg)
	CMPL	(IMMED(0),tmpreg)
#undef  tmpreg
	JNE	pending

restore_and_jmp_ml:
	POPL	temp			/* restore temp to msp */
	POPL	misc2
	
jmp_ml:
	MOVL	(IND_DW_OFF(temp,PCOffMSP),temp)
	CMPL	(limitptr, allocptr)
	JMP	temp		      /* Jump to ML code. */

pending:
	CMPL	(IMMED(0),IND_DW_OFF(vsp,InSigHandlerOffVSP))   /* Currently handling signal? */
	JNE	restore_and_jmp_ml
	MOVL	(IMMED(1),IND_DW_OFF(vsp,HandlerPendingOffVSP)) /* handler trap is now pending */

	/* must restore here because limitptr is on stack */
	POPL	temp			/* restore temp to msp */
	POPL	misc2

	MOVL	(allocptr,limitptr)
	JMP	jmp_ml			/* Jump to ML code. */

#undef  vsp

/* ----------------------------------------------------------------------
 * array : (int * 'a) -> 'a array
 * Allocate and initialize a new array.	 This can cause GC.
 */

ML_CODE_HDR(array_a)
	CHECKLIMIT(FUN_MASK)
	MOVL 	(IND_DW_OFF(stdarg,0),temp)               /* desired length into temp */
	SARL	(IMMED(1),temp)			     /* untagged */
	CMPL	(IMMED(SMALL_OBJ_SZW),temp)
	JGE	FLAB(L1)

#define	tmpreg	misc1
	PUSHL	tmpreg

	MOVL	(temp,tmpreg)		     /* build descriptor in tmpreg */
	SALL	(IMMED(TAG_SHIFTW),tmpreg)
	ORL	(IMMED(MAKE_TAG(DTAG_array)),tmpreg)
	MOVL	(tmpreg,IND_DW_OFF(allocptr,0))	     /* write descriptor */
	ADDL	(IMMED(4),allocptr)
	MOVL	(IND_DW_OFF(stdarg,4),tmpreg)	     /* initial values */
	MOVL	(allocptr,stdarg)	     /* stdarg gets ptr to new array */
	SALL	(IMMED(2),temp)		     /* length in bytes */
	ADDL	(allocptr,temp)
	XCHGL	(tmpreg,temp)		     /* tmpreg is end of array */
ANON_LAB:					     /* loop: */
	STOSL					/* 0(allocptr++) <- temp  */
	CMPL	(allocptr,tmpreg)		/* check for end of array */
	JNE	BLAB_ANON

	POPL	tmpreg
#undef  tmpreg

	CONTINUE
LABEL(L1)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_ALLOC_ARRAY), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)
	

/* create_r : int -> realarray */
ML_CODE_HDR(create_r_a)
	CHECKLIMIT(FUN_MASK)
	MOVL 	(stdarg,temp)             /* desired length into temp */
	SARL	(IMMED(1),temp)		  /* untagged */
	SHLL	(IMMED(1),temp)		  /* size in words */
	CMPL	(IMMED(SMALL_OBJ_SZW),temp)
	JGE	FLAB_ANON

#define	tmpreg	misc1
	PUSHL	tmpreg

	SHRL	(IMMED(1),temp)		     /* size in reals */
	MOVL	(temp,tmpreg)		     /* build descriptor in tmpreg */
	SALL	(IMMED(TAG_SHIFTW),tmpreg)
	ORL	(IMMED(MAKE_TAG(DTAG_realdarray)),tmpreg)
	MOVL	(tmpreg,IND_DW_OFF(allocptr,0))	     /* write descriptor */
	ADDL	(IMMED(4),allocptr)
	MOVL	(allocptr,stdarg)	     /* stdarg gets ptr to new array */
	SALL	(IMMED(3),temp)		     /* length in bytes */
	ADDL	(temp,allocptr)		     /* adjust allocptr past array */

	POPL	tmpreg
#undef  tmpreg
	CONTINUE
ANON_LAB:
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_ALLOC_REALDARRAY), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)


/* create_b : int -> bytearray */
ML_CODE_HDR(create_b_a)
	CHECKLIMIT(FUN_MASK)
	MOVL 	(stdarg,temp)                /* the length */
	SARL	(IMMED(1),temp)		     /* untagged */
	ADDL	(IMMED(3),temp)		     /* round */	
	SARL	(IMMED(2),temp)		     /* to words */
	CMPL	(IMMED(SMALL_OBJ_SZW),temp)
	JGE	FLAB_ANON

#define	tmpreg	misc1
	PUSHL	tmpreg

	MOVL	(stdarg,tmpreg)		     /* build descriptor in tmpreg */
	SARL	(IMMED(1),tmpreg)
	SALL	(IMMED(TAG_SHIFTW),tmpreg)
	ORL	(IMMED(MAKE_TAG(DTAG_bytearray)),tmpreg)
	MOVL	(tmpreg,IND_DW_OFF(allocptr,0))	     /* write descriptor */
	ADDL	(IMMED(4),allocptr)
	MOVL	(allocptr,stdarg)	     /* stdarg gets ptr to new str */
	SALL	(IMMED(2),temp)		     /* length in bytes (untagged) */
	ADDL	(temp,allocptr)		     /* allocptr += total length */

	POPL	tmpreg
#undef  tmpreg

	CONTINUE
ANON_LAB:
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_ALLOC_BYTEARRAY), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)


/* create_s : int -> string */
ML_CODE_HDR(create_s_a)
	CHECKLIMIT(FUN_MASK)
	MOVL 	(stdarg,temp)		/* the length */
	SARL	(IMMED(1),temp)		/* untagged */
	ADDL	(IMMED(4),temp)		/* round */	
	SARL	(IMMED(2),temp)		/* to words */
	CMPL	(IMMED(SMALL_OBJ_SZW),temp)
	JGE	FLAB_ANON

#define	tmpreg	misc1
	PUSHL	tmpreg

	MOVL	(stdarg,tmpreg)		     /* build descriptor in tmpreg */
	SARL	(IMMED(1),tmpreg)
	SALL	(IMMED(TAG_SHIFTW),tmpreg)
	ORL	(IMMED(MAKE_TAG(DTAG_string)),tmpreg)
	MOVL	(tmpreg,IND_DW_OFF(allocptr,0))	     /* write descriptor */
	ADDL	(IMMED(4),allocptr)
	MOVL	(allocptr,stdarg)	     /* stdarg gets ptr to new str */
	SALL	(IMMED(2),temp)		     /* length in bytes (untagged) */
	ADDL	(temp,allocptr)		     /* allocptr += total length */
	MOVL	(IMMED(0),IND_DW_OFF(allocptr,(-4)))    /* for fast strcmp */

	POPL	tmpreg
#undef  tmpreg

	CONTINUE
ANON_LAB:
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_ALLOC_STRING), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)

/* create_v_a : int * 'a list -> 'a vector
 *	creates a vector with elements taken from a list.
 *	n.b. The frontend ensures that list cannot be nil.
 */
ML_CODE_HDR(create_v_a)
	CHECKLIMIT(FUN_MASK)
	MOVL 	(IND_DW_OFF(stdarg,0),temp)	/* desired length into temp */
	SARL	(IMMED(1),temp) 		/* untagged */
	CMPL	(IMMED(SMALL_OBJ_SZW),temp)
	JGE	FLAB(L2)

#define	tmpreg	misc1
	PUSHL	tmpreg

	MOVL	(temp,tmpreg)		     /* build descriptor in tmpreg */
	SALL	(IMMED(TAG_SHIFTW),tmpreg)
	ORL	(IMMED(MAKE_TAG(DTAG_vector)),tmpreg)
	MOVL	(tmpreg,IND_DW_OFF(allocptr,0))	/* write descriptor */
	ADDL	(IMMED(4),allocptr)
	MOVL	(IND_DW_OFF(stdarg,4),tmpreg)/* list of initial values */
	MOVL	(allocptr,stdarg)	     /* stdarg gets ptr to new array */
ANON_LAB:					     /* loop: */
	MOVL	(IND_DW_OFF(tmpreg,0),temp)    	/* temp <- hd(tmpreg) */
	STOSL				        /* 0(allocptr++) <- temp */
	MOVL	(IND_DW_OFF(tmpreg,4),tmpreg)  	/* tmpreg <- tl(tmpreg) */
	CMPL	(IMMED(ML_nil),tmpreg)	     	/* end of list */
	JNE	BLAB_ANON

	POPL	tmpreg
#undef  tmpreg

	CONTINUE
LABEL(L2)
	MOVL	(mlstate_ptr, temp)
	MOVL	(IMMED(REQ_ALLOC_VECTOR), request_w)
	MOVL	(IMMED(FUN_MASK), mask)
	JMP	CSYM(set_request)
	
/* try_lock: spin_lock -> bool. 
 * low-level test-and-set style primitive for mutual-exclusion among 
 * processors.	For now, we only provide a uni-processor trivial version.
 */
ML_CODE_HDR(try_lock_a)
#if (MAX_PROCS > 1)
#  error multiple processors not supported
#else /* (MAX_PROCS == 1) */
	MOVL	((stdarg), temp)	/* Get old value of lock. */
	MOVL	(IMMED(1), (stdarg))	/* Set the lock to ML_false. */
	MOVL	(temp, stdarg)		/* Return old value of lock. */
	CONTINUE
#endif

/* unlock : releases a spin lock 
 */
ML_CODE_HDR(unlock_a)
#if (MAX_PROCS > 1)
#  error multiple processors not supported
#else /* (MAX_PROCS == 1) */
	MOVL	(IMMED(3), (stdarg))	/* Store ML_true into lock. */
	MOVL	(IMMED(1), stdarg)	/* Return unit. */
	CONTINUE
#endif


/********************* Floating point functions. *********************/

#define FPOP	fstp FP_REG(st)	/* Pop the floating point register stack. */

	DATA
	ALIGN4
GLOBAL(maxint_plus1)
WORD32(maxint_plus1,HEXLIT(40000000))  /* Used in floor_a to check for overflow. */
GLOBAL(minint_sub1)
WORD32(minint_sub1,HEXLIT(bfffffff))

/* Temporary storage for the old and new floating point control
   word.  We don't use the stack to for this, since doing so would 
   change the offsets of the pseudo-registers. */
GLOBAL(old_controlwd)
WORD16(old_controlwd,0)
GLOBAL(new_controlwd)
WORD16(new_controlwd,0)

	TEXT
	ALIGN4

/*
 * Initialize the 80387 floating point coprocessor.  First, the floating
 * point control word is initialized (undefined fields are left
 * unchanged).	Rounding control is set to "nearest" (although floor_a
 * needs "toward negative infinity").  Precision control is set to
 * "double".  The precision, underflow, denormal 
 * overflow, zero divide, and invalid operation exceptions
 * are masked.  Next, seven of the eight available entries on the
 * floating point register stack are claimed (see x86/x86.sml).
 *
 * NB: this cannot trash any registers because it's called from request_fault.
 */
ENTRY(FPEEnable)
	finit
	/* Temp space.Keep stack aligned. */
	SUBL	(IMMED(4), REG(esp))   
	/* Store FP control word. */
	fstcw	IND_W_OFF(REG(esp),0)  
	/* Keep undefined fields, clear others. */
	ANDW	(IMMED(HEXLIT(f0c0)), IND_W_OFF(REG(esp),0))
	/* Set fields (see above). */
	ORW	(IMMED(HEXLIT(023f)), IND_W_OFF(REG(esp),0))	
	fldcw	IND_W_OFF(REG(esp),0)	/* Install new control word. */
	ADDL	(IMMED(4), REG(esp))
	fldz			/* Push a zero onto the register stack. */
	fld	FP_REG(st)	/* Copy it 6 times. */
	fld	FP_REG(st)
	fld	FP_REG(st)
	fld	FP_REG(st)
	fld	FP_REG(st)
	fld	FP_REG(st)
	RET

ENTRY(fegetround)
      SUBL    (IMMED(4),REG(esp))                /* allocate temporary space */
      FSTCW   IND_W_OFF(REG(esp),0)              /* store fp control word */
	/* rounding mode is at bit 10 and 11 */
      SARL    (IMMED(10),IND_DW_OFF(REG(esp),0)) 
      ANDL    (IMMED(3),IND_DW_OFF(REG(esp),0))  /* mask two bits */
      MOVL    (IND_DW_OFF(REG(esp),0),REG(eax))  /* return rounding mode */
      ADDL    (IMMED(4),REG(esp))                /* deallocate space */
      RET
  
ENTRY(fesetround)
      SUBL    (IMMED(4),REG(esp))                /* allocate temporary space */
      FSTCW   IND_W_OFF(REG(esp),0)              /* store fp control word */
	/* Clear rounding field. */
      ANDW    (IMMED(HEXLIT(f3ff)),IND_W_OFF(REG(esp),0))
      MOVL    (IND_DW_OFF(REG(esp),8),REG(eax))  /* new rounding mode */
      SALL    (IMMED(10),REG(eax))               /* move to right place */
      ORL     (REG(eax),IND_DW_OFF(REG(esp)))    /* new control word */
      FLDCW   IND_W_OFF(REG(esp),0)              /* load new control word */
      ADDL    (IMMED(4),REG(esp))                /* deallocate space */
      RET

/* Save the state of the floating point unit. */
ENTRY(savefpregs)
	MOVL	(IND_DW_OFF(REG(esp),4), temp)	/* Get pointer argument. */
	fsave	IND_DW_OFF(temp,0)
	RET

/* Restore the state of the floating point unit. */
ENTRY(restorefpregs)
	MOVL	(IND_DW_OFF(REG(esp),4), temp)	/* Arg is an ML string. */
	frstor	IND_DW_OFF(temp,0)
	RET

/* floor : real -> int
   Return the nearest integer that is less or equal to the argument,
   or else raise Float("floor") if out of range.  This could be made 
   more efficient using integer comparisons to check for overflow. */

ML_CODE_HDR(floor_a)
	/* Get FP control word. */
	fstcw	old_controlwd
	MOVW	(old_controlwd,REG(ax))
	/* Clear rounding field. */
	ANDW	(IMMED(HEXLIT(f3ff)), REG(ax))
	/* Round towards neg. infinity. */
	ORW	(IMMED(HEXLIT(0400)), REG(ax))
	MOVW	(REG(ax), new_controlwd)
	fldcw	new_controlwd		/* Install new control word. */

	FLDL	IND_OFF(REAL8,stdarg,0)	/* Load argument. */
	FICOML	maxint_plus1		/* Compare: arg >= maxint + 1? */
	fstsw	REG(ax)			/* Get FP status word. */
	sahf				/* Copy to integer status word. */
	jae	floor_err
	FICOML	minint_sub1		/* Compare: arg <= maxint + 1? */
	fstsw	REG(ax)			/* Get FP status word. */
	sahf				/* Copy to integer status word. */
	jbe	floor_err

	SUBL	(IMMED(4), REG(esp))
	FISTPL	IND_DW_OFF(REG(esp),0)	/* Round, store, and pop. */
	POPL	stdarg
	SALL	(IMMED(1), stdarg)	/* Tag the resulting integer. */
	INCL	stdarg

	fldcw	old_controlwd		/* Restore old FP control word. */
	CONTINUE
floor_err:
	FPOP				/* Discard argument. */
	fldcw	old_controlwd		/* Restore old FP control word. */
	/* signal an overflow */
	pushf
	POPL	temp
	ORL	(IMMED(HEXLIT(800)),temp)	/* set overflow flag */
	PUSHL	temp
	popf
	into				/* can't use "int $4" here since */
					/* signal dispatch looks for into */
	/* shouldn't get here */


/* logb : real -> int
 * Extract the unbiased exponent pointed to by stdarg.
 * Note: Using fxtract, and fistl does not work for inf's and nan's.
 */
ML_CODE_HDR(logb_a)
	MOVL    (IND_DW_OFF(stdarg,4),temp) /* msb for little endian arch */
	SARL	(IMMED(20),temp)            /* throw out 20 bits */
	ANDL	(IMMED(HEXLIT(7ff)),temp)   /* clear all but 11 low bits */
	SUBL	(IMMED(1023),temp)          /* unbias */
	SALL	(IMMED(1),temp)             /* room for tag bit */
	ADDL	(IMMED(1),temp)             /* tag bit */
	MOVL	(temp,stdarg)
	CONTINUE


/* scalb : (real * int) -> real
 * Scale the first argument by 2 raised to the second argument.	 Raise
 * Float("underflow") or Float("overflow") as appropriate.
 * NB: We assume the first floating point "register" is
 * caller-save, so we can use it here (see x86/x86.sml). */

ML_CODE_HDR(scalb_a)
	CHECKLIMIT(FUN_MASK)
	PUSHL	IND_DW_OFF(stdarg,4)		/* Get copy of scalar. */
	SARL	(IMMED(1),IND_DW_OFF(REG(esp),0))	/* Untag it. */
	FILDL	IND_DW_OFF(REG(esp),0)			/* Load it ... */
	fstp	FP_REG(st)(1)			/* ... into 1st FP reg. */
	ADDL	(IMMED(4), REG(esp))		/* Discard copy of scalar. */

	MOVL	(IND_DW_OFF(stdarg,0), temp)	/* Get pointer to real. */
	FLDL	IND_OFF(REAL8,temp,0)		/* Load it into temp. */

	fscale				/* Multiply exponent by scalar. */
	MOVL	(IMMED(DESC_reald), IND_DW_OFF(allocptr,0))
	FSTPL	IND_OFF(REAL8,allocptr,4)	/* Store resulting float. */
	ADDL	(IMMED(4),allocptr)		/* Allocate word for tag. */
	MOVL	(allocptr, stdarg)	/* Return a pointer to the float. */
	ADDL	(IMMED(8), allocptr)		/* Allocate room for float. */
	CONTINUE

END

/* end of X86.prim.masm (MS assembler) */



root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0