diff options
Diffstat (limited to 'private/crt32/misc')
109 files changed, 24457 insertions, 0 deletions
diff --git a/private/crt32/misc/_strerr.c b/private/crt32/misc/_strerr.c new file mode 100644 index 000000000..8863e64c5 --- /dev/null +++ b/private/crt32/misc/_strerr.c @@ -0,0 +1,143 @@ +/*** +*_strerr.c - routine for indexing into system error list +* +* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Returns system error message index by errno; conforms to the +* XENIX standard, much compatibility with 1983 uniforum draft standard. +* +*Revision History: +* 02-24-87 JCR Renamed this routine from "strerror" to "_strerror" +* for MS. The new "strerror" routine conforms to the +* ANSI interface. +* 11-10-87 SKS Remove IBMC20 switch +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-05-87 JCR Mthread support +* 05-31-88 PHG Merged DLL and normal versions +* 06-06-89 JCR 386 mthread support +* 11-20-89 GJF Fixed copyright, indents. Removed unreferenced local. +* Added const attribute to type of message +* 03-13-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h> +* 07-25-90 SBM Removed redundant include (stdio.h) +* 10-04-90 GJF New-style function declarator. +* 07-18-91 GJF Multi-thread support for Win32 [_WIN32_]. +* 02-17-93 GJF Changed for new _getptd(). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <errmsg.h> +#include <syserr.h> +#include <string.h> +#include <malloc.h> +#include <os2dll.h> + +/* Max length of message = user_string(94)+system_string+2 */ +/* [NOTE: The mthread error message buffer is shared by both strerror + and _strerror so must be the max length of both. */ +#define _ERRMSGLEN_ 94+_SYS_MSGMAX+2 + +/*** +*char *_strerror(message) - get system error message +* +*Purpose: +* builds an error message consisting of the users error message +* (the message parameter), followed by ": ", followed by the system +* error message (index through errno), followed by a newline. If +* message is NULL or a null string, returns a pointer to just +* the system error message. +* +*Entry: +* char *message - user's message to prefix system error message +* +*Exit: +* returns pointer to static memory containing error message. +* returns NULL if malloc() fails in multi-thread versions. +* +*Exceptions: +* +*******************************************************************************/ + +char * _CRTAPI1 _strerror ( + REG1 const char *message + ) +{ +#ifdef MTHREAD + +#ifdef _CRUISER_ + + struct _tiddata * tdata; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + _ptiddata ptd = _getptd(); + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + char *bldmsg; + +#else + + static char bldmsg[_ERRMSGLEN_]; + +#endif + + +#ifdef MTHREAD + +#ifdef _CRUISER_ + + /* Use per thread buffer area (malloc space, if necessary) */ + /* [NOTE: This buffer is shared between _strerror and streror.] */ + tdata = _gettidtab(); /* get tid's data address */ + if (tdata->_errmsg == NULL) + if ( (tdata->_errmsg = malloc(_ERRMSGLEN_)) == NULL) + return(NULL); + bldmsg = tdata->_errmsg; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + /* Use per thread buffer area (malloc space, if necessary) */ + /* [NOTE: This buffer is shared between _strerror and streror.] */ + + if ( (ptd->_errmsg == NULL) && ((ptd->_errmsg = malloc(_ERRMSGLEN_)) + == NULL) ) + return(NULL); + bldmsg = ptd->_errmsg; + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + +#endif + + /* Build the error message */ + + bldmsg[0] = '\0'; + + if (message && *message) { + strcat( bldmsg, message ); + strcat( bldmsg, ": " ); + } + + strcat( bldmsg, _sys_err_msg( errno ) ); + + return( strcat( bldmsg, "\n" ) ); +} diff --git a/private/crt32/misc/abort.c b/private/crt32/misc/abort.c new file mode 100644 index 000000000..b88d2fff0 --- /dev/null +++ b/private/crt32/misc/abort.c @@ -0,0 +1,96 @@ +/*** +*abort.c - abort a program by raising SIGABRT +* +* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines abort() - print a message and raise SIGABRT. +* +*Revision History: +* 06-30-89 PHG module created, based on asm version +* 03-13-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 07-26-90 SBM Removed bogus leading underscore from _NMSG_WRITE +* 10-04-90 GJF New-style function declarator. +* 10-11-90 GJF Now does raise(SIGABRT). Also changed _NMSG_WRITE() +* interface. +* 04-10-91 PNT Added _MAC_ conditional +* 08-26-92 GJF Include unistd.h for POSIX build. +* +*******************************************************************************/ + +#include <cruntime.h> +#ifdef _POSIX_ +#include <unistd.h> +#endif +#include <stdlib.h> +#include <internal.h> +#include <rterr.h> +#include <signal.h> + +/*** +*void abort() - abort the current program by raising SIGABRT +* +*Purpose: +* print out an abort message and raise the SIGABRT signal. If the user +* hasn't defined an abort handler routine, terminate the program +* with exit status of 3 without cleaning up. +* +* Multi-thread version does not raise SIGABRT -- this isn't supported +* under multi-thread. +* +*Entry: +* None. +* +*Exit: +* Does not return. +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 abort ( + void + ) +{ + _NMSG_WRITE(_RT_ABORT); /* write the abort message */ + +#ifdef _POSIX_ + + { + sigset_t set; + + fflush(NULL); + + signal(SIGABRT, SIG_DFL); + + sigemptyset(&set); + sigaddset(&set, SIGABRT); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + +#endif /* _POSIX_ */ + + +#ifndef _MAC_ + + raise(SIGABRT); /* raise abort signal */ + +#endif /* ndef _MAC_ */ + + /* We usually won't get here, but it's possible that + SIGABRT was ignored. So hose the program anyway. */ + +#ifdef _POSIX_ + /* SIGABRT was ignored or handled, and the handler returned + normally. We need open streams to be flushed here. */ + + exit(3); +#else /* not _POSIX_ */ + + _exit(3); +#endif /* _POSIX */ +} diff --git a/private/crt32/misc/abs.c b/private/crt32/misc/abs.c new file mode 100644 index 000000000..cd5f3d1be --- /dev/null +++ b/private/crt32/misc/abs.c @@ -0,0 +1,51 @@ +/*** +*abs.c - find absolute value +* +* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines abs() - find the absolute value of an int. +* +*Revision History: +* 04-22-87 JMB added function pragma for conversion to C 5.0 compiler +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned up +* the formatting a bit. +* 10-04-90 GJF New-style function declarator. +* 12-28-90 SRW Added _CRUISER_ conditional around function pragma +* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too. +* 03-09-94 RDL Enable #pragma function for MIPS _WIN32_ builds too. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> + +#ifdef _MSC_VER +#pragma function(abs) +#endif + +/*** +*int abs(number) - find absolute value of number +* +*Purpose: +* Returns the absolute value of number (if number >= 0, returns number, +* else returns -number). +* +*Entry: +* int number - number to find absolute value of +* +*Exit: +* returns the aboslute value of number +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 abs ( + int number + ) +{ + return( number>=0 ? number : -number ); +} diff --git a/private/crt32/misc/alpha/chandler.c b/private/crt32/misc/alpha/chandler.c new file mode 100644 index 000000000..68251f1ca --- /dev/null +++ b/private/crt32/misc/alpha/chandler.c @@ -0,0 +1,296 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + chandler.c + +Abstract: + + This module implements the C specific exception handler that provides + structured condition handling for the C language. + +Author: + + David N. Cutler (davec) 11-Sep-1990 + +Environment: + + Any mode. + +Revision History: + + Thomas Van Baak (tvb) 29-Apr-1992 + + Adapted for Alpha AXP. + +--*/ + +#include "nt.h" + +// +// Define procedure prototypes for exception filter and termination handler +// execution routines defined in jmpuwind.s. +// + +LONG +__C_ExecuteExceptionFilter ( + PEXCEPTION_POINTERS ExceptionPointers, + EXCEPTION_FILTER ExceptionFilter, + ULONG EstablisherFrame + ); + +VOID +__C_ExecuteTerminationHandler ( + BOOLEAN AbnormalTermination, + TERMINATION_HANDLER TerminationHandler, + ULONG EstablisherFrame + ); + +EXCEPTION_DISPOSITION +__C_specific_handler ( + IN struct _EXCEPTION_RECORD *ExceptionRecord, + IN void *EstablisherFrame, + IN OUT struct _CONTEXT *ContextRecord, + IN OUT struct _DISPATCHER_CONTEXT *DispatcherContext + ) + +/*++ + +Routine Description: + + This function scans the scope tables associated with the specified + procedure and calls exception and termination handlers as necessary. + + This language specific exception handler function is called on a + per-frame basis and in two different cases: + + First, the IS_DISPATCHING case, it is called by the exception + dispatcher, RtlDispatchException, via the short assembler routine, + __C_ExecuteHandlerForException, when trying to locate exception + filters within the given frame. + + Second, the IS_UNWINDING case, it is called by the frame unwinder, + RtlUnwind, via the short assembler routine, __C_ExecuteHandlerForUnwind, + when unwinding the stack and trying to locate termination handlers + within the given frame. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + EstablisherFrame - Supplies a pointer to frame of the establisher function. + + ContextRecord - Supplies a pointer to a context record. + + DispatcherContext - Supplies a pointer to the exception dispatcher or + unwind dispatcher context. + +Return Value: + + If the exception is handled by one of the exception filter routines, then + there is no return from this routine and RtlUnwind is called. Otherwise, + an exception disposition value of continue execution or continue search is + returned. + +--*/ + +{ + + ULONG ControlPc; + EXCEPTION_FILTER ExceptionFilter; + EXCEPTION_POINTERS ExceptionPointers; + PRUNTIME_FUNCTION FunctionEntry; + ULONG Index; + PSCOPE_TABLE ScopeTable; + ULONG TargetPc; + TERMINATION_HANDLER TerminationHandler; + LONG Value; + + // + // Get the address of where control left the establisher, the address of + // the function table entry that describes the function, and the address of + // the scope table. + // + + ControlPc = DispatcherContext->ControlPc; + FunctionEntry = DispatcherContext->FunctionEntry; + ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData); + + // + // The scope table HandlerAddress is either the address of an exception + // filter or a termination handler. The C compiler wraps the code in the + // exception filter expression or the termination handler clause within + // an internal C function. The value of the scope table JumpTarget field + // is used to distinguish an exception filter function (JumpTarget non zero) + // from a termination handler function (JumpTarget is zero). + // + + // + // If an unwind is not in progress, then scan the scope table and call + // the appropriate exception filter routines. Otherwise, scan the scope + // table and call the appropriate termination handlers using the target + // PC obtained from the context record. + // + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { + + // + // Set up the ExceptionPointers structure that is passed as the argument + // to the exception filter. It is used by the compiler to implement the + // intrinsic functions exception_code() and exception_info(). + // + + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + + // + // Scan the scope table and call the appropriate exception filter + // routines. The scope table entries are known to be sorted by + // increasing EndAddress order. Thus a linear scan will naturally + // hit inner scope exception clauses before outer scope clauses. + // + + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) && + (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) { + + // + // Call the exception filter routine. + // + + ExceptionFilter = + (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress; + Value = __C_ExecuteExceptionFilter(&ExceptionPointers, + ExceptionFilter, + (ULONG)EstablisherFrame); + + // + // If the return value is less than zero, then dismiss the + // exception. Otherwise, if the value is greater than zero, + // then unwind to the target exception handler corresponding + // to the exception filter. Otherwise, continue the search for + // an exception filter. + // + + // + // Exception filters will usually return one of the following + // defines, although the decision below is made only by sign: + // + // #define EXCEPTION_EXECUTE_HANDLER 1 + // #define EXCEPTION_CONTINUE_SEARCH 0 + // #define EXCEPTION_CONTINUE_EXECUTION -1 + // + + if (Value < 0) { + return ExceptionContinueExecution; + + } else if (Value > 0) { + + // + // Set the return value for the unwind to the exception + // code so the exception handler clause can retrieve it + // from v0. This is how GetExceptionCode() is implemented + // in exception handler clauses. + // + + RtlUnwind(EstablisherFrame, + (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget, + ExceptionRecord, + (PVOID)ExceptionRecord->ExceptionCode); + } + } + } + + } else { + + // + // Scan the scope table and call the appropriate termination handler + // routines. + // + + TargetPc = (ULONG)ContextRecord->Fir; + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) { + + // + // If the target PC is within the same scope the control PC + // is within, then this is an uplevel goto out of an inner try + // scope or a long jump back into a try scope. Terminate the + // scan for termination handlers - because any other handlers + // will be outside the scope of both the goto and its label. + // + // N.B. The target PC can be just beyond the end of the scope, + // in which case it is a leave from the scope. + // + + if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) { + break; + + } else { + + // + // If the scope table entry describes an exception filter + // and the associated exception handler is the target of + // the unwind, then terminate the scan for termination + // handlers. Otherwise, if the scope table entry describes + // a termination handler, then record the address of the + // end of the scope as the new control PC address and call + // the termination handler. + // + // Recording a new control PC is necessary to ensure that + // termination handlers are called only once even when a + // collided unwind occurs. + // + + if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) { + + // + // try/except - exception filter (JumpTarget != 0). + // After the exception filter is called, the exception + // handler clause is executed by the call to unwind + // above. Having reached this point in the scan of the + // scope tables, any other termination handlers will + // be outside the scope of the try/except. + // + + if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) { + break; + } + + } else { + + // + // try/finally - termination handler (JumpTarget == 0). + // + + // + // Unless the termination handler results in a long + // jump, execution will resume at the instruction after + // the exception handler clause. + // + // ## tvb - I'm still suspicious of the +4 below. + + DispatcherContext->ControlPc = + ScopeTable->ScopeRecord[Index].EndAddress + 4; + TerminationHandler = + (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress; + __C_ExecuteTerminationHandler(TRUE, + TerminationHandler, + (ULONG)EstablisherFrame); + } + } + } + } + } + + // + // Continue search for exception filters or termination handlers. + // + + return ExceptionContinueSearch; +} diff --git a/private/crt32/misc/alpha/divdat.s b/private/crt32/misc/alpha/divdat.s new file mode 100644 index 000000000..543d6237b --- /dev/null +++ b/private/crt32/misc/alpha/divdat.s @@ -0,0 +1,597 @@ + + # Copyright 1992,1993, Digital Equipment Corporation + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + # 009 15 Jul 1992 KDG - Can't have .end for Alpha/OSF - use + # new ots_data_end macro + # - Need .data for OSF + # + # 010 4 Sep 1992 KDG Switch PSECT from ots_div_data to ots_lit + # + # 011 26 Jan 1993 KDG Add underscore, OSF uses CS name + # + # 012 5 Apr 1993 WBN Use 16-byte entries, up to 512, and + # support computing 1/(a+x). + +#include "ots_defs.hs" + + # Data area description + # + # The data area "ots_div_data" is an array of structures, indexed + # by the divisor value, with each array entry being 16 bytes in size + # formatted as follows: + # + # 6 1 1 + # 3 6 5 6 5 0 + # +-------+-------+-------+-------+-------+-------+-------+-------+ + # | 32 bit reciprocal (48 bits) | recip^2 |shift| + # +-------+-------+-------+-------+-------+-------+-------+-------+ + # | 64 bit reciprocal | + # +---------------------------------------------------------------+ + # + # The 64-bit reciprocal has the leading '1' bit omitted, so it provides + # 65 bits of precision -- enough to handle unsigned 64-bit dividends. + # + # The first quadword contains the 6-bit shift amount needed to handle + # 64-bit cases and powers of two. For divisors between 256 and 512, + # this quadword also contains a 10-bit coefficient for linearly + # approximating larger reciprocals (1/(a+x) = 1/a - x/a^2 + ...). + # + # The 32-bit reciprocal has the shift count built in, so a UMULH gives + # the correct quotient without shifting. The reciprocal needs 33 bits + # of precision. The 10-bit reciprocal-squared, and 6-bit shift amount, + # are noise in the reciprocal that can be ignored for divisors less than + # 512. (The only possible exception is for 1/257, and it checks out OK.) + # + # Powers of two are flagged with a 32-bit reciprocal that is negative, + # and a 64-bit reciprocal that is zero. + + # OTS division data table + # + +#ifdef VMS + .psect ots_lit + .align 4 # octaword alignment +ots_div_data:: +#endif +#ifdef OSF + .globl _OtsDivData + .data + .align 4 +_OtsDivData: +#endif +#ifdef WNT + .globl _OtsDivData + .data + .align 4 +_OtsDivData: +#endif + # recip^2--. .-shift + #32b recip / \| 64 bit reciprocal divisor + .quad 0x0000000000000000, 0x0000000000000000 # 0 + .quad 0x8000000000000000, 0x0000000000000000 # 1 + .quad 0x8000000000000001, 0x0000000000000000 # 2 + .quad 0x5555555555560002, 0x5555555555555556 # 3 + .quad 0x8000000000000002, 0x0000000000000000 # 4 + .quad 0x3333333333340003, 0x999999999999999A # 5 + .quad 0x2AAAAAAAAAAB0003, 0x5555555555555556 # 6 + .quad 0x24924924924A0003, 0x2492492492492493 # 7 + .quad 0x8000000000000003, 0x0000000000000000 # 8 + .quad 0x1C71C71C71C80004, 0xC71C71C71C71C71D # 9 + .quad 0x19999999999A0004, 0x999999999999999A # 10 + .quad 0x1745D1745D180004, 0x745D1745D1745D18 # 11 + .quad 0x1555555555560004, 0x5555555555555556 # 12 + .quad 0x13B13B13B13C0004, 0x3B13B13B13B13B14 # 13 + .quad 0x1249249249250004, 0x2492492492492493 # 14 + .quad 0x1111111111120004, 0x1111111111111112 # 15 + .quad 0x8000000000000004, 0x0000000000000000 # 16 + .quad 0x0F0F0F0F0F100005, 0xE1E1E1E1E1E1E1E2 # 17 + .quad 0x0E38E38E38E40005, 0xC71C71C71C71C71D # 18 + .quad 0x0D79435E50D80005, 0xAF286BCA1AF286BD # 19 + .quad 0x0CCCCCCCCCCD0005, 0x999999999999999A # 20 + .quad 0x0C30C30C30C40005, 0x8618618618618619 # 21 + .quad 0x0BA2E8BA2E8C0005, 0x745D1745D1745D18 # 22 + .quad 0x0B21642C85910005, 0x642C8590B21642C9 # 23 + .quad 0x0AAAAAAAAAAB0005, 0x5555555555555556 # 24 + .quad 0x0A3D70A3D70B0005, 0x47AE147AE147AE15 # 25 + .quad 0x09D89D89D89E0005, 0x3B13B13B13B13B14 # 26 + .quad 0x097B425ED0980005, 0x2F684BDA12F684BE # 27 + .quad 0x0924924924930005, 0x2492492492492493 # 28 + .quad 0x08D3DCB08D3E0005, 0x1A7B9611A7B9611B # 29 + .quad 0x0888888888890005, 0x1111111111111112 # 30 + .quad 0x0842108421090005, 0x0842108421084211 # 31 + .quad 0x8000000000000005, 0x0000000000000000 # 32 + .quad 0x07C1F07C1F080006, 0xF07C1F07C1F07C20 # 33 + .quad 0x0787878787880006, 0xE1E1E1E1E1E1E1E2 # 34 + .quad 0x0750750750760006, 0xD41D41D41D41D41E # 35 + .quad 0x071C71C71C720006, 0xC71C71C71C71C71D # 36 + .quad 0x06EB3E45306F0006, 0xBACF914C1BACF915 # 37 + .quad 0x06BCA1AF286C0006, 0xAF286BCA1AF286BD # 38 + .quad 0x06906906906A0006, 0xA41A41A41A41A41B # 39 + .quad 0x0666666666670006, 0x999999999999999A # 40 + .quad 0x063E7063E7070006, 0x8F9C18F9C18F9C19 # 41 + .quad 0x0618618618620006, 0x8618618618618619 # 42 + .quad 0x05F417D05F420006, 0x7D05F417D05F417E # 43 + .quad 0x05D1745D17460006, 0x745D1745D1745D18 # 44 + .quad 0x05B05B05B05C0006, 0x6C16C16C16C16C17 # 45 + .quad 0x0590B21642C90006, 0x642C8590B21642C9 # 46 + .quad 0x0572620AE4C50006, 0x5C9882B931057263 # 47 + .quad 0x0555555555560006, 0x5555555555555556 # 48 + .quad 0x05397829CBC20006, 0x4E5E0A72F0539783 # 49 + .quad 0x051EB851EB860006, 0x47AE147AE147AE15 # 50 + .quad 0x0505050505060006, 0x4141414141414142 # 51 + .quad 0x04EC4EC4EC4F0006, 0x3B13B13B13B13B14 # 52 + .quad 0x04D4873ECADF0006, 0x3521CFB2B78C1353 # 53 + .quad 0x04BDA12F684C0006, 0x2F684BDA12F684BE # 54 + .quad 0x04A7904A79050006, 0x29E4129E4129E413 # 55 + .quad 0x04924924924A0006, 0x2492492492492493 # 56 + .quad 0x047DC11F70480006, 0x1F7047DC11F7047E # 57 + .quad 0x0469EE58469F0006, 0x1A7B9611A7B9611B # 58 + .quad 0x0456C797DD4A0006, 0x15B1E5F75270D046 # 59 + .quad 0x0444444444450006, 0x1111111111111112 # 60 + .quad 0x04325C53EF370006, 0x0C9714FBCDA3AC11 # 61 + .quad 0x0421084210850006, 0x0842108421084211 # 62 + .quad 0x0410410410420006, 0x0410410410410411 # 63 + .quad 0x8000000000000006, 0x0000000000000000 # 64 + .quad 0x03F03F03F0400007, 0xF81F81F81F81F820 # 65 + .quad 0x03E0F83E0F840007, 0xF07C1F07C1F07C20 # 66 + .quad 0x03D226357E170007, 0xE9131ABF0B7672A1 # 67 + .quad 0x03C3C3C3C3C40007, 0xE1E1E1E1E1E1E1E2 # 68 + .quad 0x03B5CC0ED7310007, 0xDAE6076B981DAE61 # 69 + .quad 0x03A83A83A83B0007, 0xD41D41D41D41D41E # 70 + .quad 0x039B0AD120740007, 0xCD85689039B0AD13 # 71 + .quad 0x038E38E38E390007, 0xC71C71C71C71C71D # 72 + .quad 0x0381C0E070390007, 0xC0E070381C0E0704 # 73 + .quad 0x03759F2298380007, 0xBACF914C1BACF915 # 74 + .quad 0x0369D0369D040007, 0xB4E81B4E81B4E81C # 75 + .quad 0x035E50D794360007, 0xAF286BCA1AF286BD # 76 + .quad 0x03531DEC0D4D0007, 0xA98EF606A63BD81B # 77 + .quad 0x0348348348350007, 0xA41A41A41A41A41B # 78 + .quad 0x033D91D2A2070007, 0x9EC8E951033D91D3 # 79 + .quad 0x0333333333340007, 0x999999999999999A # 80 + .quad 0x0329161F9ADE0007, 0x948B0FCD6E9E0653 # 81 + .quad 0x031F3831F3840007, 0x8F9C18F9C18F9C19 # 82 + .quad 0x03159721ED7F0007, 0x8ACB90F6BF3A9A38 # 83 + .quad 0x030C30C30C310007, 0x8618618618618619 # 84 + .quad 0x0303030303040007, 0x8181818181818182 # 85 + .quad 0x02FA0BE82FA10007, 0x7D05F417D05F417E # 86 + .quad 0x02F149902F150007, 0x78A4C8178A4C8179 # 87 + .quad 0x02E8BA2E8BA30007, 0x745D1745D1745D18 # 88 + .quad 0x02E05C0B81710007, 0x702E05C0B81702E1 # 89 + .quad 0x02D82D82D82E0007, 0x6C16C16C16C16C17 # 90 + .quad 0x02D02D02D02E0007, 0x6816816816816817 # 91 + .quad 0x02C8590B21650007, 0x642C8590B21642C9 # 92 + .quad 0x02C0B02C0B030007, 0x6058160581605817 # 93 + .quad 0x02B9310572630007, 0x5C9882B931057263 # 94 + .quad 0x02B1DA46102C0007, 0x58ED2308158ED231 # 95 + .quad 0x02AAAAAAAAAB0007, 0x5555555555555556 # 96 + .quad 0x02A3A0FD5C600007, 0x51D07EAE2F8151D1 # 97 + .quad 0x029CBC14E5E10007, 0x4E5E0A72F0539783 # 98 + .quad 0x0295FAD40A580007, 0x4AFD6A052BF5A815 # 99 + .quad 0x028F5C28F5C30007, 0x47AE147AE147AE15 # 100 + .quad 0x0288DF0CAC5C0007, 0x446F86562D9FAEE5 # 101 + .quad 0x0282828282830007, 0x4141414141414142 # 102 + .quad 0x027C45979C960007, 0x3E22CBCE4A9027C5 # 103 + .quad 0x0276276276280007, 0x3B13B13B13B13B14 # 104 + .quad 0x0270270270280007, 0x3813813813813814 # 105 + .quad 0x026A439F65700007, 0x3521CFB2B78C1353 # 106 + .quad 0x02647C6945630007, 0x323E34A2B10BF66F # 107 + .quad 0x025ED097B4260007, 0x2F684BDA12F684BE # 108 + .quad 0x02593F69B0260007, 0x2C9FB4D812C9FB4E # 109 + .quad 0x0253C8253C830007, 0x29E4129E4129E413 # 110 + .quad 0x024E6A1710250007, 0x27350B88127350B9 # 111 + .quad 0x0249249249250007, 0x2492492492492493 # 112 + .quad 0x0243F6F024400007, 0x21FB78121FB78122 # 113 + .quad 0x023EE08FB8240007, 0x1F7047DC11F7047E # 114 + .quad 0x0239E0D5B4510007, 0x1CF06ADA2811CF07 # 115 + .quad 0x0234F72C23500007, 0x1A7B9611A7B9611B # 116 + .quad 0x0230230230240007, 0x1811811811811812 # 117 + .quad 0x022B63CBEEA50007, 0x15B1E5F75270D046 # 118 + .quad 0x0226B90226BA0007, 0x135C81135C81135D # 119 + .quad 0x0222222222230007, 0x1111111111111112 # 120 + .quad 0x021D9EAD7CD40007, 0x0ECF56BE69C8FDE3 # 121 + .quad 0x02192E29F79C0007, 0x0C9714FBCDA3AC11 # 122 + .quad 0x0214D0214D030007, 0x0A6810A6810A6811 # 123 + .quad 0x0210842108430007, 0x0842108421084211 # 124 + .quad 0x020C49BA5E360007, 0x0624DD2F1A9FBE77 # 125 + .quad 0x0208208208210007, 0x0410410410410411 # 126 + .quad 0x0204081020410007, 0x0204081020408103 # 127 + .quad 0x8000000000000007, 0x0000000000000000 # 128 + .quad 0x01FC07F01FC10008, 0xFC07F01FC07F01FD # 129 + .quad 0x01F81F81F8200008, 0xF81F81F81F81F820 # 130 + .quad 0x01F44659E4A50008, 0xF44659E4A4271580 # 131 + .quad 0x01F07C1F07C20008, 0xF07C1F07C1F07C20 # 132 + .quad 0x01ECC07B301F0008, 0xECC07B301ECC07B4 # 133 + .quad 0x01E9131ABF0C0008, 0xE9131ABF0B7672A1 # 134 + .quad 0x01E573AC901F0008, 0xE573AC901E573ACA # 135 + .quad 0x01E1E1E1E1E20008, 0xE1E1E1E1E1E1E1E2 # 136 + .quad 0x01DE5D6E3F890008, 0xDE5D6E3F8868A471 # 137 + .quad 0x01DAE6076B990008, 0xDAE6076B981DAE61 # 138 + .quad 0x01D77B654B830008, 0xD77B654B82C33918 # 139 + .quad 0x01D41D41D41E0008, 0xD41D41D41D41D41E # 140 + .quad 0x01D0CB58F6ED0008, 0xD0CB58F6EC07432E # 141 + .quad 0x01CD8568903A0008, 0xCD85689039B0AD13 # 142 + .quad 0x01CA4B3055EF0008, 0xCA4B3055EE19101D # 143 + .quad 0x01C71C71C71D0008, 0xC71C71C71C71C71D # 144 + .quad 0x01C3F8F01C400008, 0xC3F8F01C3F8F01C4 # 145 + .quad 0x01C0E070381D0008, 0xC0E070381C0E0704 # 146 + .quad 0x01BDD2B899410008, 0xBDD2B899406F74AF # 147 + .quad 0x01BACF914C1C0008, 0xBACF914C1BACF915 # 148 + .quad 0x01B7D6C3DDA40008, 0xB7D6C3DDA338B2B0 # 149 + .quad 0x01B4E81B4E820008, 0xB4E81B4E81B4E81C # 150 + .quad 0x01B2036406C90008, 0xB2036406C80D901C # 151 + .quad 0x01AF286BCA1B0008, 0xAF286BCA1AF286BD # 152 + .quad 0x01AC5701AC580008, 0xAC5701AC5701AC58 # 153 + .quad 0x01A98EF606A70008, 0xA98EF606A63BD81B # 154 + .quad 0x01A6D01A6D020008, 0xA6D01A6D01A6D01B # 155 + .quad 0x01A41A41A41B0008, 0xA41A41A41A41A41B # 156 + .quad 0x01A16D3F97A50008, 0xA16D3F97A4B01A17 # 157 + .quad 0x019EC8E951040008, 0x9EC8E951033D91D3 # 158 + .quad 0x019C2D14EE4B0008, 0x9C2D14EE4A1019C3 # 159 + .quad 0x01999999999A0008, 0x999999999999999A # 160 + .quad 0x01970E4F80CC0008, 0x970E4F80CB8727C1 # 161 + .quad 0x01948B0FCD6F0008, 0x948B0FCD6E9E0653 # 162 + .quad 0x01920FB49D0F0008, 0x920FB49D0E228D5A # 163 + .quad 0x018F9C18F9C20008, 0x8F9C18F9C18F9C19 # 164 + .quad 0x018D3018D3020008, 0x8D3018D3018D3019 # 165 + .quad 0x018ACB90F6C00008, 0x8ACB90F6BF3A9A38 # 166 + .quad 0x01886E5F0ABC0008, 0x886E5F0ABB04994C # 167 + .quad 0x0186186186190008, 0x8618618618618619 # 168 + .quad 0x0183C977AB2C0008, 0x83C977AB2BEDD28F # 169 + .quad 0x0181818181820008, 0x8181818181818182 # 170 + .quad 0x017F405FD0180008, 0x7F405FD017F405FE # 171 + .quad 0x017D05F417D10008, 0x7D05F417D05F417E # 172 + .quad 0x017AD2208E0F0008, 0x7AD2208E0ECC3546 # 173 + .quad 0x0178A4C8178B0008, 0x78A4C8178A4C8179 # 174 + .quad 0x01767DCE434B0008, 0x767DCE434A9B1018 # 175 + .quad 0x01745D1745D20008, 0x745D1745D1745D18 # 176 + .quad 0x01724287F46E0008, 0x724287F46DEBC05D # 177 + .quad 0x01702E05C0B90008, 0x702E05C0B81702E1 # 178 + .quad 0x016E1F76B4340008, 0x6E1F76B4337C6CB2 # 179 + .quad 0x016C16C16C170008, 0x6C16C16C16C16C17 # 180 + .quad 0x016A13CD15380008, 0x6A13CD153729043F # 181 + .quad 0x0168168168170008, 0x6816816816816817 # 182 + .quad 0x01661EC6A5130008, 0x661EC6A5122F9017 # 183 + .quad 0x01642C8590B30008, 0x642C8590B21642C9 # 184 + .quad 0x01623FA770170008, 0x623FA7701623FA78 # 185 + .quad 0x0160581605820008, 0x6058160581605817 # 186 + .quad 0x015E75BB8D020008, 0x5E75BB8D015E75BC # 187 + .quad 0x015C9882B9320008, 0x5C9882B931057263 # 188 + .quad 0x015AC056B0160008, 0x5AC056B015AC056C # 189 + .quad 0x0158ED2308160008, 0x58ED2308158ED231 # 190 + .quad 0x01571ED3C5070008, 0x571ED3C506B39A23 # 191 + .quad 0x0155555555560008, 0x5555555555555556 # 192 + .quad 0x015390948F410008, 0x5390948F40FEAC70 # 193 + .quad 0x0151D07EAE300008, 0x51D07EAE2F8151D1 # 194 + .quad 0x0150150150160008, 0x5015015015015016 # 195 + .quad 0x014E5E0A72F10008, 0x4E5E0A72F0539783 # 196 + .quad 0x014CAB88725B0008, 0x4CAB88725AF6E750 # 197 + .quad 0x014AFD6A052C0008, 0x4AFD6A052BF5A815 # 198 + .quad 0x0149539E3B2E0008, 0x49539E3B2D066EA3 # 199 + .quad 0x0147AE147AE20008, 0x47AE147AE147AE15 # 200 + .quad 0x01460CBC7F5D0008, 0x460CBC7F5CF9A1C1 # 201 + .quad 0x01446F86562E0008, 0x446F86562D9FAEE5 # 202 + .quad 0x0142D6625D520008, 0x42D6625D51F86EFA # 203 + .quad 0x0141414141420008, 0x4141414141414142 # 204 + .quad 0x013FB013FB020008, 0x3FB013FB013FB014 # 205 + .quad 0x013E22CBCE4B0008, 0x3E22CBCE4A9027C5 # 206 + .quad 0x013C995A47BB0008, 0x3C995A47BABE7441 # 207 + .quad 0x013B13B13B140008, 0x3B13B13B13B13B14 # 208 + .quad 0x013991C2C1880008, 0x3991C2C187F63372 # 209 + .quad 0x0138138138140008, 0x3813813813813814 # 210 + .quad 0x013698DF3DE10008, 0x3698DF3DE0747954 # 211 + .quad 0x013521CFB2B80008, 0x3521CFB2B78C1353 # 212 + .quad 0x0133AE45B57C0008, 0x33AE45B57BCB1E0D # 213 + .quad 0x01323E34A2B20008, 0x323E34A2B10BF66F # 214 + .quad 0x0130D190130E0008, 0x30D190130D190131 # 215 + .quad 0x012F684BDA130008, 0x2F684BDA12F684BE # 216 + .quad 0x012E025C04B90008, 0x2E025C04B8097013 # 217 + .quad 0x012C9FB4D8130008, 0x2C9FB4D812C9FB4E # 218 + .quad 0x012B404AD0130008, 0x2B404AD012B404AE # 219 + .quad 0x0129E4129E420008, 0x29E4129E4129E413 # 220 + .quad 0x01288B01288C0008, 0x288B01288B01288C # 221 + .quad 0x0127350B88130008, 0x27350B88127350B9 # 222 + .quad 0x0125E227080A0008, 0x25E22708092F1139 # 223 + .quad 0x0124924924930008, 0x2492492492492493 # 224 + .quad 0x0123456789AC0008, 0x23456789ABCDF013 # 225 + .quad 0x0121FB7812200008, 0x21FB78121FB78122 # 226 + .quad 0x0120B470C67D0008, 0x20B470C67C0D8876 # 227 + .quad 0x011F7047DC120008, 0x1F7047DC11F7047E # 228 + .quad 0x011E2EF3B3FC0008, 0x1E2EF3B3FB874432 # 229 + .quad 0x011CF06ADA290008, 0x1CF06ADA2811CF07 # 230 + .quad 0x011BB4A4046F0008, 0x1BB4A4046ED29012 # 231 + .quad 0x011A7B9611A80008, 0x1A7B9611A7B9611B # 232 + .quad 0x0119453808CB0008, 0x19453808CA29C047 # 233 + .quad 0x0118118118120008, 0x1811811811811812 # 234 + .quad 0x0116E06894280008, 0x16E0689427378EB5 # 235 + .quad 0x0115B1E5F7530008, 0x15B1E5F75270D046 # 236 + .quad 0x011485F0E0AD0008, 0x1485F0E0ACD3B68D # 237 + .quad 0x01135C81135D0008, 0x135C81135C81135D # 238 + .quad 0x0112358E75D40008, 0x12358E75D30336A1 # 239 + .quad 0x0111111111120008, 0x1111111111111112 # 240 + .quad 0x010FEF010FF00008, 0x0FEF010FEF010FF0 # 241 + .quad 0x010ECF56BE6A0008, 0x0ECF56BE69C8FDE3 # 242 + .quad 0x010DB20A88F50008, 0x0DB20A88F469598D # 243 + .quad 0x010C9714FBCE0008, 0x0C9714FBCDA3AC11 # 244 + .quad 0x010B7E6EC25A0008, 0x0B7E6EC259DC7936 # 245 + .quad 0x010A6810A6820008, 0x0A6810A6810A6811 # 246 + .quad 0x010953F390110008, 0x0953F39010953F3A # 247 + .quad 0x0108421084220008, 0x0842108421084211 # 248 + .quad 0x01073260A4800008, 0x073260A47F7C66D0 # 249 + .quad 0x010624DD2F1B0008, 0x0624DD2F1A9FBE77 # 250 + .quad 0x0105197F7D740008, 0x05197F7D73404147 # 251 + .quad 0x0104104104110008, 0x0410410410410411 # 252 + .quad 0x0103091B51F60008, 0x03091B51F5E1A4EF # 253 + .quad 0x0102040810210008, 0x0204081020408103 # 254 + .quad 0x0101010101020008, 0x0101010101010102 # 255 + .quad 0x800000000000FFC8, 0x0000000000000000 # 256 + .quad 0x00FF00FF0100FE09, 0xFE01FE01FE01FE02 # 257 + .quad 0x00FE03F80FE1FC09, 0xFC07F01FC07F01FD # 258 + .quad 0x00FD08E55010FA09, 0xFA11CAA01FA11CAB # 259 + .quad 0x00FC0FC0FC10F849, 0xF81F81F81F81F820 # 260 + .quad 0x00FB18856507F649, 0xF6310ACA0DBB574C # 261 + .quad 0x00FA232CF253F489, 0xF44659E4A4271580 # 262 + .quad 0x00F92FB22119F289, 0xF25F644230AB50CB # 263 + .quad 0x00F83E0F83E1F0C9, 0xF07C1F07C1F07C20 # 264 + .quad 0x00F74E3FC22DEF09, 0xEE9C7F8458E01EEA # 265 + .quad 0x00F6603D9810ED09, 0xECC07B301ECC07B4 # 266 + .quad 0x00F57403D5D1EB49, 0xEAE807ABA01EAE81 # 267 + .quad 0x00F4898D5F86E989, 0xE9131ABF0B7672A1 # 268 + .quad 0x00F3A0D52CBBE7C9, 0xE741AA59750E466D # 269 + .quad 0x00F2B9D64810E649, 0xE573AC901E573ACA # 270 + .quad 0x00F1D48BCEE1E489, 0xE3A9179DC1A733F5 # 271 + .quad 0x00F0F0F0F0F1E2C9, 0xE1E1E1E1E1E1E1E2 # 272 + .quad 0x00F00F00F010E109, 0xE01E01E01E01E01F # 273 + .quad 0x00EF2EB71FC5DF89, 0xDE5D6E3F8868A471 # 274 + .quad 0x00EE500EE501DDC9, 0xDCA01DCA01DCA01E # 275 + .quad 0x00ED7303B5CDDC49, 0xDAE6076B981DAE61 # 276 + .quad 0x00EC979118F4DAC9, 0xD92F2231E7F89B44 # 277 + .quad 0x00EBBDB2A5C2D909, 0xD77B654B82C33918 # 278 + .quad 0x00EAE56403ACD789, 0xD5CAC807572B201E # 279 + .quad 0x00EA0EA0EA0FD609, 0xD41D41D41D41D41E # 280 + .quad 0x00E939651FE3D489, 0xD272CA3FC5B1A6B9 # 281 + .quad 0x00E865AC7B77D309, 0xD0CB58F6EC07432E # 282 + .quad 0x00E79372E226D189, 0xCF26E5C44BFC61B3 # 283 + .quad 0x00E6C2B4481DD009, 0xCD85689039B0AD13 # 284 + .quad 0x00E5F36CB00FCE89, 0xCBE6D9601CBE6D97 # 285 + .quad 0x00E525982AF8CD09, 0xCA4B3055EE19101D # 286 + .quad 0x00E45932D7DDCBC9, 0xC8B265AFB8A4201D # 287 + .quad 0x00E38E38E38FCA49, 0xC71C71C71C71C71D # 288 + .quad 0x00E2C4A6886BC8C9, 0xC5894D10D4985C20 # 289 + .quad 0x00E1FC780E20C789, 0xC3F8F01C3F8F01C4 # 290 + .quad 0x00E135A9C976C609, 0xC26B5392EA01C26C # 291 + .quad 0x00E070381C0FC4C9, 0xC0E070381C0E0704 # 292 + .quad 0x00DFAC1F7435C389, 0xBF583EE868D8AEBF # 293 + .quad 0x00DEE95C4CA1C209, 0xBDD2B899406F74AF # 294 + .quad 0x00DE27EB2C42C0C9, 0xBC4FD65883E7B3A3 # 295 + .quad 0x00DD67C8A60EBF89, 0xBACF914C1BACF915 # 296 + .quad 0x00DCA8F158C8BE49, 0xB951E2B18FF23571 # 297 + .quad 0x00DBEB61EED2BD09, 0xB7D6C3DDA338B2B0 # 298 + .quad 0x00DB2F171DF8BBC9, 0xB65E2E3BEEE05232 # 299 + .quad 0x00DA740DA741BA89, 0xB4E81B4E81B4E81C # 300 + .quad 0x00D9BA4256C1B949, 0xB37484AD806CDD22 # 301 + .quad 0x00D901B20365B809, 0xB2036406C80D901C # 302 + .quad 0x00D84A598ECAB6C9, 0xB094B31D922A3E86 # 303 + .quad 0x00D79435E50EB589, 0xAF286BCA1AF286BD # 304 + .quad 0x00D6DF43FCA5B449, 0xADBE87F94905E01B # 305 + .quad 0x00D62B80D62CB349, 0xAC5701AC5701AC58 # 306 + .quad 0x00D578E97C40B209, 0xAAF1D2F87EBFCAA2 # 307 + .quad 0x00D4C77B0354B0C9, 0xA98EF606A63BD81B # 308 + .quad 0x00D417328988AFC9, 0xA82E65130E158A5C # 309 + .quad 0x00D3680D3681AE89, 0xA6D01A6D01A6D01B # 310 + .quad 0x00D2BA083B45AD89, 0xA574107688A4A157 # 311 + .quad 0x00D20D20D20EAC49, 0xA41A41A41A41A41B # 312 + .quad 0x00D161543E29AB49, 0xA2C2A87C51CA04E9 # 313 + .quad 0x00D0B69FCBD3AA49, 0xA16D3F97A4B01A17 # 314 + .quad 0x00D00D00D00EA909, 0xA01A01A01A01A01B # 315 + .quad 0x00CF6474A882A809, 0x9EC8E951033D91D3 # 316 + .quad 0x00CEBCF8BB5CA709, 0x9D79F176B682D396 # 317 + .quad 0x00CE168A7726A609, 0x9C2D14EE4A1019C3 # 318 + .quad 0x00CD712752A9A4C9, 0x9AE24EA5510DA484 # 319 + .quad 0x00CCCCCCCCCDA3C9, 0x999999999999999A # 320 + .quad 0x00CC29786C77A2C9, 0x9852F0D8EC0FF33E # 321 + .quad 0x00CB8727C066A1C9, 0x970E4F80CB8727C1 # 322 + .quad 0x00CAE5D85F1CA0C9, 0x95CBB0BE377AD92B # 323 + .quad 0x00CA4587E6B89FC9, 0x948B0FCD6E9E0653 # 324 + .quad 0x00C9A633FCDA9EC9, 0x934C67F9B2CE601A # 325 + .quad 0x00C907DA4E889DC9, 0x920FB49D0E228D5A # 326 + .quad 0x00C86A78900D9D09, 0x90D4F120190D4F13 # 327 + .quad 0x00C7CE0C7CE19C09, 0x8F9C18F9C18F9C19 # 328 + .quad 0x00C73293D78A9B09, 0x8E6527AF1373F071 # 329 + .quad 0x00C6980C69819A09, 0x8D3018D3018D3019 # 330 + .quad 0x00C5FE7403189949, 0x8BFCE8062FF3A019 # 331 + .quad 0x00C565C87B609849, 0x8ACB90F6BF3A9A38 # 332 + .quad 0x00C4CE07B00D9749, 0x899C0F601899C0F7 # 333 + .quad 0x00C4372F855E9689, 0x886E5F0ABB04994C # 334 + .quad 0x00C3A13DE6059589, 0x87427BCC092B8EE7 # 335 + .quad 0x00C30C30C30D9489, 0x8618618618618619 # 336 + .quad 0x00C2780613C193C9, 0x84F00C2780613C04 # 337 + .quad 0x00C1E4BBD59692C9, 0x83C977AB2BEDD28F # 338 + .quad 0x00C152500C169209, 0x82A4A0182A4A0183 # 339 + .quad 0x00C0C0C0C0C19149, 0x8181818181818182 # 340 + .quad 0x00C0300C03019049, 0x8060180601806019 # 341 + .quad 0x00BFA02FE80C8F89, 0x7F405FD017F405FE # 342 + .quad 0x00BF112A8AD38E89, 0x7E225515A4F1D1BA # 343 + .quad 0x00BE82FA0BE98DC9, 0x7D05F417D05F417E # 344 + .quad 0x00BDF59C91718D09, 0x7BEB3922E017BEB4 # 345 + .quad 0x00BD691047088C49, 0x7AD2208E0ECC3546 # 346 + .quad 0x00BCDD535DB28B49, 0x79BAA6BB6398B6F7 # 347 + .quad 0x00BC52640BC68A89, 0x78A4C8178A4C8179 # 348 + .quad 0x00BBC8408CD789C9, 0x77908119AC60D342 # 349 + .quad 0x00BB3EE721A68909, 0x767DCE434A9B1018 # 350 + .quad 0x00BAB656100C8849, 0x756CAC201756CAC3 # 351 + .quad 0x00BA2E8BA2E98789, 0x745D1745D1745D18 # 352 + .quad 0x00B9A7862A1086C9, 0x734F0C541FE8CB10 # 353 + .quad 0x00B92143FA378609, 0x724287F46DEBC05D # 354 + .quad 0x00B89BC36CE48549, 0x713786D9C7C08A75 # 355 + .quad 0x00B81702E05D8489, 0x702E05C0B81702E1 # 356 + .quad 0x00B79300B79483C9, 0x6F26016F26016F27 # 357 + .quad 0x00B70FBB5A1A8309, 0x6E1F76B4337C6CB2 # 358 + .quad 0x00B68D31340F8249, 0x6D1A62681C860FB1 # 359 + .quad 0x00B60B60B60C8189, 0x6C16C16C16C16C17 # 360 + .quad 0x00B58A48551980C9, 0x6B1490AA31A3CFC8 # 361 + .quad 0x00B509E68A9C8009, 0x6A13CD153729043F # 362 + .quad 0x00B48A39D4477F49, 0x691473A88D0BFD2E # 363 + .quad 0x00B40B40B40C7E89, 0x6816816816816817 # 364 + .quad 0x00B38CF9B00C7E09, 0x6719F36016719F37 # 365 + .quad 0x00B30F63528A7D49, 0x661EC6A5122F9017 # 366 + .quad 0x00B2927C29DB7C89, 0x6524F853B4AA339F # 367 + .quad 0x00B21642C85A7C09, 0x642C8590B21642C9 # 368 + .quad 0x00B19AB5C4577B49, 0x63356B88AC0DE017 # 369 + .quad 0x00B11FD3B80C7A89, 0x623FA7701623FA78 # 370 + .quad 0x00B0A59B418E7A09, 0x614B36831AE93AA7 # 371 + .quad 0x00B02C0B02C17949, 0x6058160581605817 # 372 + .quad 0x00AFB321A14A7889, 0x5F66434292DFBE1D # 373 + .quad 0x00AF3ADDC6817809, 0x5E75BB8D015E75BC # 374 + .quad 0x00AEC33E1F687749, 0x5D867C3ECE2A534A # 375 + .quad 0x00AE4C415C9976C9, 0x5C9882B931057263 # 376 + .quad 0x00ADD5E632407609, 0x5BABCC647FA9150D # 377 + .quad 0x00AD602B580B7589, 0x5AC056B015AC056C # 378 + .quad 0x00ACEB0F891F74C9, 0x59D61F123CCAA377 # 379 + .quad 0x00AC7691840B7449, 0x58ED2308158ED231 # 380 + .quad 0x00AC02B00AC17389, 0x5805601580560159 # 381 + .quad 0x00AB8F69E2847309, 0x571ED3C506B39A23 # 382 + .quad 0x00AB1CBDD3E37249, 0x56397BA7C52E1EC0 # 383 + .quad 0x00AAAAAAAAAB71C9, 0x5555555555555556 # 384 + .quad 0x00AA392F35DD7149, 0x54725E6BB82FE016 # 385 + .quad 0x00A9C84A47A17089, 0x5390948F40FEAC70 # 386 + .quad 0x00A957FAB5417009, 0x52AFF56A8054ABFE # 387 + .quad 0x00A8E83F57186F89, 0x51D07EAE2F8151D1 # 388 + .quad 0x00A87917088F6EC9, 0x50F22E111C4C56DF # 389 + .quad 0x00A80A80A80B6E49, 0x5015015015015016 # 390 + .quad 0x00A79C7B16EB6DC9, 0x4F38F62DD4C9A845 # 391 + .quad 0x00A72F0539796D49, 0x4E5E0A72F0539783 # 392 + .quad 0x00A6C21DF6E26CC9, 0x4D843BEDC2C4B900 # 393 + .quad 0x00A655C4392E6C09, 0x4CAB88725AF6E750 # 394 + .quad 0x00A5E9F6ED356B89, 0x4BD3EDDA68FE0E43 # 395 + .quad 0x00A57EB502966B09, 0x4AFD6A052BF5A815 # 396 + .quad 0x00A513FD6BB16A89, 0x4A27FAD76014A280 # 397 + .quad 0x00A4A9CF1D976A09, 0x49539E3B2D066EA3 # 398 + .quad 0x00A44029100B6989, 0x4880522014880523 # 399 + .quad 0x00A3D70A3D7168C9, 0x47AE147AE147AE15 # 400 + .quad 0x00A36E71A2CC6849, 0x46DCE34596066251 # 401 + .quad 0x00A3065E3FAF67C9, 0x460CBC7F5CF9A1C1 # 402 + .quad 0x00A29ECF163C6749, 0x453D9E2C776CA015 # 403 + .quad 0x00A237C32B1766C9, 0x446F86562D9FAEE5 # 404 + .quad 0x00A1D13985606649, 0x43A2730ABEE4D1DC # 405 + .quad 0x00A16B312EA965C9, 0x42D6625D51F86EFA # 406 + .quad 0x00A105A932F36549, 0x420B5265E595123E # 407 + .quad 0x00A0A0A0A0A164C9, 0x4141414141414142 # 408 + .quad 0x00A03C1688746449, 0x40782D10E6566065 # 409 + .quad 0x009FD809FD8163C9, 0x3FB013FB013FB014 # 410 + .quad 0x009F747A152E6349, 0x3EE8F42A5AF06DA1 # 411 + .quad 0x009F1165E72662C9, 0x3E22CBCE4A9027C5 # 412 + .quad 0x009EAECC8D546249, 0x3D5D991AA75C5BBE # 413 + .quad 0x009E4CAD23DE6209, 0x3C995A47BABE7441 # 414 + .quad 0x009DEB06C91A6189, 0x3BD60D923295482D # 415 + .quad 0x009D89D89D8A6109, 0x3B13B13B13B13B14 # 416 + .quad 0x009D2921C3D76089, 0x3A524387AC822610 # 417 + .quad 0x009CC8E160C46009, 0x3991C2C187F63372 # 418 + .quad 0x009C69169B315F89, 0x38D22D366088DBF4 # 419 + .quad 0x009C09C09C0A5F09, 0x3813813813813814 # 420 + .quad 0x009BAADE8E4B5EC9, 0x3755BD1C945EDC20 # 421 + .quad 0x009B4C6F9EF15E49, 0x3698DF3DE0747954 # 422 + .quad 0x009AEE72FCFA5DC9, 0x35DCE5F9F2AF821F # 423 + .quad 0x009A90E7D95C5D49, 0x3521CFB2B78C1353 # 424 + .quad 0x009A33CD67015D09, 0x34679ACE0134679B # 425 + .quad 0x0099D722DABE5C89, 0x33AE45B57BCB1E0D # 426 + .quad 0x00997AE76B515C09, 0x32F5CED6A1DFA014 # 427 + .quad 0x00991F1A51595B89, 0x323E34A2B10BF66F # 428 + .quad 0x0098C3BAC7505B49, 0x3187758E9EBB6014 # 429 + .quad 0x009868C809875AC9, 0x30D190130D190131 # 430 + .quad 0x00980E4156215A49, 0x301C82AC40260391 # 431 + .quad 0x0097B425ED0A5A09, 0x2F684BDA12F684BE # 432 + .quad 0x00975A750FF75989, 0x2EB4EA1FED14B15F # 433 + .quad 0x0097012E025D5909, 0x2E025C04B8097013 # 434 + .quad 0x0096A850096B58C9, 0x2D50A012D50A012E # 435 + .quad 0x00964FDA6C0A5849, 0x2C9FB4D812C9FB4E # 436 + .quad 0x0095F7CC72D257C9, 0x2BEF98E5A3710FD2 # 437 + .quad 0x0095A025680A5789, 0x2B404AD012B404AE # 438 + .quad 0x009548E4979F5709, 0x2A91C92F3C1053FA # 439 + .quad 0x0094F2094F2156C9, 0x29E4129E4129E413 # 440 + .quad 0x00949B92DDC15649, 0x293725BB804A4DCA # 441 + .quad 0x0094458094465609, 0x288B01288B01288C # 442 + .quad 0x0093EFD1C50F5589, 0x27DFA38A1CE4D6F9 # 443 + .quad 0x00939A85C40A5509, 0x27350B88127350B9 # 444 + .quad 0x0093459BE6B154C9, 0x268B37CD601268B4 # 445 + .quad 0x0092F11384055449, 0x25E22708092F1139 # 446 + .quad 0x00929CEBF48C5409, 0x2539D7E9177B21CB # 447 + .quad 0x00924924924A5389, 0x2492492492492493 # 448 + .quad 0x0091F5BCB8BC5349, 0x23EB79717605B39A # 449 + .quad 0x0091A2B3C4D652C9, 0x23456789ABCDF013 # 450 + .quad 0x0091500915015289, 0x22A0122A0122A013 # 451 + .quad 0x0090FDBC09105209, 0x21FB78121FB78122 # 452 + .quad 0x0090ABCC024351C9, 0x21579804855E6013 # 453 + .quad 0x00905A38633F5189, 0x20B470C67C0D8876 # 454 + .quad 0x00900900900A5109, 0x2012012012012013 # 455 + .quad 0x008FB823EE0950C9, 0x1F7047DC11F7047E # 456 + .quad 0x008F67A1E3FE5049, 0x1ECF43C7FB84C2F1 # 457 + .quad 0x008F1779D9FE5009, 0x1E2EF3B3FB874432 # 458 + .quad 0x008EC7AB39734FC9, 0x1D8F5672E4ABC83B # 459 + .quad 0x008E78356D154F49, 0x1CF06ADA2811CF07 # 460 + .quad 0x008E2917E0E84F09, 0x1C522FC1CE058D9B # 461 + .quad 0x008DDA5202384E89, 0x1BB4A4046ED29012 # 462 + .quad 0x008D8BE33F964E49, 0x1B17C67F2BAE2B21 # 463 + .quad 0x008D3DCB08D44E09, 0x1A7B9611A7B9611B # 464 + .quad 0x008CF008CF014D89, 0x19E0119E0119E012 # 465 + .quad 0x008CA29C04664D49, 0x19453808CA29C047 # 466 + .quad 0x008C55841C824D09, 0x18AB083902BDAB95 # 467 + .quad 0x008C08C08C094C89, 0x1811811811811812 # 468 + .quad 0x008BBC50C8DF4C49, 0x1778A191BD684181 # 469 + .quad 0x008B70344A144C09, 0x16E0689427378EB5 # 470 + .quad 0x008B246A87E24BC9, 0x1648D50FC3201165 # 471 + .quad 0x008AD8F2FBAA4B49, 0x15B1E5F75270D046 # 472 + .quad 0x008A8DCD1FEF4B09, 0x151B9A3FDD5C8CB9 # 473 + .quad 0x008A42F870574AC9, 0x1485F0E0ACD3B68D # 474 + .quad 0x0089F87469A34A49, 0x13F0E8D3447241C1 # 475 + .quad 0x0089AE4089AF4A09, 0x135C81135C81135D # 476 + .quad 0x0089645C4F6F49C9, 0x12C8B89EDC0ABBD8 # 477 + .quad 0x00891AC73AEA4989, 0x12358E75D30336A1 # 478 + .quad 0x0088D180CD3B4909, 0x11A3019A748267AF # 479 + .quad 0x00888888888948C9, 0x1111111111111112 # 480 + .quad 0x00883FDDF0094889, 0x107FBBE01107FBBF # 481 + .quad 0x0087F78087F84849, 0x0FEF010FEF010FF0 # 482 + .quad 0x0087AF6FD59A4809, 0x0F5EDFAB325A1A81 # 483 + .quad 0x008767AB5F354789, 0x0ECF56BE69C8FDE3 # 484 + .quad 0x00872032AC144749, 0x0E40655826010E41 # 485 + .quad 0x0086D905447B4709, 0x0DB20A88F469598D # 486 + .quad 0x00869222B1AD46C9, 0x0D24456359E39D2D # 487 + .quad 0x00864B8A7DE74689, 0x0C9714FBCDA3AC11 # 488 + .quad 0x0086053C345B4649, 0x0C0A7868B41708E7 # 489 + .quad 0x0085BF37612D4609, 0x0B7E6EC259DC7936 # 490 + .quad 0x0085797B91784589, 0x0AF2F722EECB5713 # 491 + .quad 0x0085340853414549, 0x0A6810A6810A6811 # 492 + .quad 0x0084EEDD357D4509, 0x09DDBA6AF836010A # 493 + .quad 0x0084A9F9C80944C9, 0x0953F39010953F3A # 494 + .quad 0x0084655D9BAC4489, 0x08CABB37565E2011 # 495 + .quad 0x0084210842114449, 0x0842108421084211 # 496 + .quad 0x0083DCF94DC84409, 0x07B9F29B8EAE19C2 # 497 + .quad 0x00839930524043C9, 0x073260A47F7C66D0 # 498 + .quad 0x008355ACE3C94389, 0x06AB59C7912FB620 # 499 + .quad 0x0083126E978E4309, 0x0624DD2F1A9FBE77 # 500 + .quad 0x0082CF75039442C9, 0x059EEA0727586633 # 501 + .quad 0x00828CBFBEBA4289, 0x05197F7D73404147 # 502 + .quad 0x00824A4E60B44249, 0x04949CC1664C578A # 503 + .quad 0x0082082082094209, 0x0410410410410411 # 504 + .quad 0x0081C635BC1341C9, 0x038C6B78247FBF1D # 505 + .quad 0x0081848DA8FB4189, 0x03091B51F5E1A4EF # 506 + .quad 0x00814327E3BA4149, 0x02864FC7729E8C5F # 507 + .quad 0x0081020408114109, 0x0204081020408103 # 508 + .quad 0x0080C121B28C40C9, 0x0182436517A37530 # 509 + .quad 0x0080808080814089, 0x0101010101010102 # 510 + .quad 0x0080402010094049, 0x0080402010080403 # 511 + .quad 0x8000000000004009, 0x0000000000000000 # 512 + diff --git a/private/crt32/misc/alpha/divide.s b/private/crt32/misc/alpha/divide.s new file mode 100644 index 000000000..cff0254e7 --- /dev/null +++ b/private/crt32/misc/alpha/divide.s @@ -0,0 +1,1319 @@ +// TITLE("Slow Integer Division and Remainder") +//++ +// +// Copyright (c) 1992 Digital Equipment Corporation +// +// Module Name: +// +// divide.s +// +// Abstract: +// +// This module implements integer division and remainder routines that are +// called by assembler pseudo-ops. +// +// Author: +// +// Ken Lesniak (lesniak) 15-Jun-1990 +// Thomas Van Baak (tvb) 13-Jun-1992 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + +// +// Implementation Notes: +// +// There are no Alpha machine instructions for performing integer division +// (divl, divlu, divq, divqu) or remainder (reml, remlu, remq, remqu). The +// machine instructions generated for these assembler pseudo instructions +// are dependent on the operands. +// +// Division and remainder by constant values are replaced with a sequence +// of instructions that depend on the data type and the value of the +// constant. Shifting or reciprocal multiplication are used in most cases +// to generate the result. +// +// Division and remainder by non-constant values are replaced with a +// procedure call to a library routine to perform the operation. This file +// contains those routines. +// +// This code is adapted from the Alpha/OSF versions by Ken Lesniak and are +// based on a simple shift/subtract algorithm. Higher performance versions +// are available and so these functions are now obsolete. +// +// Longword register arguments are explicitly converted to canonical form +// because these functions, with their non-standard calling sequence, act +// more like instructions than procedure calls. Longword instructions do +// not require canonical longword operands, but standard procedures with +// longword register arguments, may assume the caller has passed canonical +// longwords. +// + +// +// Define common stack frame for all the functions in this file. +// + + .struct 0 + +DiS0: .space 8 // save register s0 +DiS1: .space 8 // save register s1 + +DiS2: .space 8 // save register s2 +DiS3: .space 8 // save register s3 + +DiTy: .space 8 // save register t11 +DiTr: .space 8 // save register t9 + +DiRa: .space 8 // save register ra + .space 8 // ensure 16-byte stack alignment + +DiFrameLength: // length of stack frame + +// +// Define non-standard calling standard arguments. +// +// These have been changed more than once so until they are permanent, +// symbolic names will be used instead of conventional register names. +// + +#define Tr t9 // return address +#define Tx t10 // dividend and result +#define Ty t11 // divisor + + SBTTL("Signed Long Integer Division") +//++ +// +// LONG +// __divl ( +// IN LONG Dividend, +// IN LONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 32-bit integer by a signed 32-bit integer +// and returns the signed 32-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (quotient) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__divl, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s2, DiS2(sp) // save non volatile registers + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + + addl Tx, 0, Tx // make sure dividend is in canonical form + addl Ty, 0, Ty // make sure divisor is in canonical form + +// +// Check for division of the most negative integer (INT_MIN) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addl Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise + mov Tx, s1 // copy dividend + cmovne s0, 0, s1 // replace w/ 0 if divisor != -1 + sublv zero, s1, s1 // trap if dividend = INT_MIN + +// +// Save sign of quotient for later. Convert negative arguments to positive for +// the division algorithm. +// + + xor Tx, Ty, s2 // compute sign of quotient + cmplt Tx, 0, s0 // sign of dividend is sign of remainder + bic s2, 1, s2 // use low bit for remainder sign + bis s0, s2, s2 // merge in with quotient sign + + subl zero, Tx, s0 // negate dividend + cmovlt Tx, s0, Tx // get absolute value of dividend + subl zero, Ty, s0 // negate divisor + cmovlt Ty, s0, Ty // get absolute value of divisor + +// +// Perform the shift/subtract loop 8 times and 4 bits per loop. +// + + ldiq s0, 32/4 // loop iterations + + sll Ty, 32, Ty // move divisor up to high 32 bits + zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits + +10: addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + subq s0, 1, s0 // any more iterations? + bne s0, 10b // + +// +// Restore sign of quotient and return value in Tx. +// + + addl Tx, 0, Tx // get quotient into canonical form + + subl zero, Tx, s0 // negate quotient into a temp + cmovlt s2, s0, Tx // if quotient should be negative copy temp + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __divl + + SBTTL("Unsigned Long Integer Division") +//++ +// +// ULONG +// __divlu ( +// IN ULONG Dividend, +// IN ULONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 32-bit integer by an unsigned 32-bit +// integer and returns the unsigned 32-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (quotient) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__divlu, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s1, DiS1(sp) // save non volatile registers + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Perform the shift/subtract loop 8 times and 4 bits per loop. +// + + ldiq s0, 32/4 // set iteration count + + sll Ty, 32, Ty // move divisor up to high 32 bits + zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits + +10: addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + subq s0, 1, s0 // any more iterations? + bne s0, 10b // + +// +// Finished with return value in Tx. +// + + addl Tx, 0, Tx // get quotient into canonical form + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __divlu + + SBTTL("Signed Quad Integer Division") +//++ +// +// QUAD +// __divq ( +// IN QUAD Dividend, +// IN QUAD Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 64-bit integer by a signed 64-bit integer +// and returns the signed 64-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (quotient) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__divq, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s3, DiS3(sp) // save non volatile registers + stq s2, DiS2(sp) // + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Check for division of the most negative integer (QUAD_MIN) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addq Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise + mov Tx, s1 // copy dividend + cmovne s0, 0, s1 // replace w/ 0 if divisor != -1 + subqv zero, s1, s1 // trap if dividend = LONG_MIN + +// +// Save sign of quotient for later. Convert negative arguments to positive for +// the division algorithm. +// + + xor Tx, Ty, s2 // compute sign of quotient + cmplt Tx, 0, s0 // sign of dividend is sign of remainder + bic s2, 1, s2 // use low bit for remainder sign + bis s0, s2, s2 // merge in with quotient sign + + subq zero, Tx, s0 // negate dividend + cmovlt Tx, s0, Tx // get absolute value of dividend + subq zero, Ty, s0 // negate divisor + cmovlt Ty, s0, Ty // get absolute value of divisor + +// +// Perform the shift/subtract loop 16 times and 4 bits per loop. +// + + ldiq s1, 0 // zero-extend dividend to 128 bits + + ldiq s3, 64/4 // loop iterations + +10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + subq s3, 1, s3 // any more iterations? + bne s3, 10b // + +// +// Restore sign of quotient and return value in Tx. +// + + subq zero, Tx, s0 // negate quotient into a temp + cmovlt s2, s0, Tx // if quotient should be negative copy temp + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + ldq s3, DiS3(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __divq + + SBTTL("Unsigned Quad Integer Division") +//++ +// +// UQUAD +// __divqu ( +// IN UQUAD Dividend, +// IN UQUAD Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 64-bit integer by an unsigned 64-bit +// integer and returns the unsigned 64-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (quotient) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__divqu, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq s2, DiS2(sp) // save non volatile registers + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Perform the shift/subtract loop 16 times and 4 bits per loop. +// + + ldiq s2, 64/4 // set iteration count + + ldiq s1, 0 // zero-extend dividend to 128 bits + +10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + subq s2, 1, s2 // any more iterations? + bne s2, 10b // + +// +// Finished with return value in Tx. +// + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __divqu + + SBTTL("Signed Long Integer Remainder") +//++ +// +// LONG +// __reml ( +// IN LONG Dividend, +// IN LONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 32-bit integer by a signed 32-bit integer +// and returns the signed 32-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (remainder) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__reml, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s2, DiS2(sp) // save non volatile registers + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + + addl Tx, 0, Tx // make sure dividend is in canonical form + addl Ty, 0, Ty // make sure divisor is in canonical form + +// +// Check for division of the most negative integer (INT_MIN) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addl Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise + mov Tx, s1 // copy dividend + cmovne s0, 0, s1 // replace w/ 0 if divisor != -1 + sublv zero, s1, s1 // trap if dividend = INT_MIN + +// +// Save sign of quotient for later. Convert negative arguments to positive for +// the division algorithm. +// + + xor Tx, Ty, s2 // compute sign of quotient + cmplt Tx, 0, s0 // sign of dividend is sign of remainder + bic s2, 1, s2 // use low bit for remainder sign + bis s0, s2, s2 // merge in with quotient sign + + subl zero, Tx, s0 // negate dividend + cmovlt Tx, s0, Tx // get absolute value of dividend + subl zero, Ty, s0 // negate divisor + cmovlt Ty, s0, Ty // get absolute value of divisor + +// +// Perform the shift/subtract loop 8 times and 4 bits per loop. +// + + ldiq s0, 32/4 // loop iterations + + sll Ty, 32, Ty // move divisor up to high 32 bits + zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits + +10: addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + subq s0, 1, s0 // any more iterations? + bne s0, 10b // + +// +// Restore sign of remainder and return value in Tx. +// + + sra Tx, 32, Tx // extract remainder in canonical form + subl zero, Tx, s0 // negate remainder into a temp + cmovlbs s2, s0, Tx // if remainder should be negative copy temp + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __reml + + SBTTL("Unsigned Long Integer Remainder") +//++ +// +// ULONG +// __remlu ( +// IN ULONG Dividend, +// IN ULONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 32-bit integer by an unsigned 32-bit +// integer and returns the unsigned 32-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (remainder) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__remlu, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s1, DiS1(sp) // save non volatile registers + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Perform the shift/subtract loop 8 times and 4 bits per loop. +// + + ldiq s0, 32/4 // set iteration count + + sll Ty, 32, Ty // move divisor up to high 32 bits + zap Tx, 0xf0, Tx // zero-extend dividend to 64 bits + +10: addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + addq Tx, Tx, Tx // shift dividend left a bit + + cmpule Ty, Tx, s1 // is dividend >= divisor? + addq Tx, s1, Tx // set quotient bit if dividend >= divisor + subq Tx, Ty, s1 // subtract divisor from dividend... + cmovlbs Tx, s1, Tx // ...if dividend >= divisor + + subq s0, 1, s0 // any more iterations? + bne s0, 10b // + +// +// Finished with return value in Tx. +// + + sra Tx, 32, Tx // extract remainder in canonical form + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __remlu + + SBTTL("Signed Quad Integer Remainder") +//++ +// +// QUAD +// __remq ( +// IN QUAD Dividend, +// IN QUAD Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 64-bit integer by a signed 64-bit integer +// and returns the signed 64-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (remainder) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__remq, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq Ty, DiTy(sp) // save original divisor + stq s3, DiS3(sp) // save non volatile registers + stq s2, DiS2(sp) // + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Check for division of the most negative integer (QUAD_MIN) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addq Ty, 1, s0 // 0 if Ty == -1; != 0 otherwise + mov Tx, s1 // copy dividend + cmovne s0, 0, s1 // replace w/ 0 if divisor != -1 + subqv zero, s1, s1 // trap if dividend = LONG_MIN + +// +// Save sign of quotient for later. Convert negative arguments to positive for +// the division algorithm. +// + + xor Tx, Ty, s2 // compute sign of quotient + cmplt Tx, 0, s0 // sign of dividend is sign of remainder + bic s2, 1, s2 // use low bit for remainder sign + bis s0, s2, s2 // merge in with quotient sign + + subq zero, Tx, s0 // negate dividend + cmovlt Tx, s0, Tx // get absolute value of dividend + subq zero, Ty, s0 // negate divisor + cmovlt Ty, s0, Ty // get absolute value of divisor + +// +// Perform the shift/subtract loop 16 times and 4 bits per loop. +// + + ldiq s1, 0 // zero-extend dividend to 128 bits + + ldiq s3, 64/4 // loop iterations + +10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + subq s3, 1, s3 // any more iterations? + bne s3, 10b // + +// +// Restore sign of remainder and return value in Tx. +// + + subq zero, s1, Tx // copy negated remainder to return register + cmovlbc s2, s1, Tx // if positive remainder then overwrite + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + ldq s3, DiS3(sp) // + ldq Ty, DiTy(sp) // restore original divisor + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __remq + + SBTTL("Unsigned Quad Integer Remainder") +//++ +// +// UQUAD +// __remqu ( +// IN UQUAD Dividend, +// IN UQUAD Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 64-bit integer by an unsigned 64-bit +// integer and returns the unsigned 64-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (remainder) is returned in register t10. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__remqu, DiFrameLength, Tr) + + lda sp, -DiFrameLength(sp) // allocate stack frame + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + stq ra, DiRa(sp) // save ra register + stq ra, DiTr(sp) // backtrace return address + stq Tr, DiTr(sp) // save actual return address + + stq s2, DiS2(sp) // save non volatile registers + stq s1, DiS1(sp) // + stq s0, DiS0(sp) // + + PROLOGUE_END + +// +// Check for division by zero. +// + + beq Ty, 20f // die if divisor is zero + +// +// Perform the shift/subtract loop 16 times and 4 bits per loop. +// + + ldiq s2, 64/4 // set iteration count + + ldiq s1, 0 // zero-extend dividend to 128 bits + +10: cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + cmplt Tx, 0, s0 // predict carry-out of low-dividend shift + addq Tx, Tx, Tx // shift low-dividend left + addq s1, s1, s1 // shift high-dividend left + bis s1, s0, s1 // merge in carry-out of low-dividend + + cmpule Ty, s1, s0 // is dividend >= divisor? + addq Tx, s0, Tx // set quotient bit if dividend >= divisor + subq s1, Ty, s0 // subtract divisor from dividend... + cmovlbs Tx, s0, s1 // ...if dividend >= divisor + + subq s2, 1, s2 // any more iterations? + bne s2, 10b // + +// +// Finished with return value in Tx. +// + + mov s1, Tx // get remainder + + ldq s0, DiS0(sp) // restore saved registers + ldq s1, DiS1(sp) // + ldq s2, DiS2(sp) // + + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + +// +// Generate an exception for divide by zero. Return a zero quotient if the +// caller continues execution. +// + +20: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldil Tx, 0 // return zero quotient + lda sp, DiFrameLength(sp) // deallocate stack frame + ret zero, (Tr) // return + + .end __remqu diff --git a/private/crt32/misc/alpha/divide2.s b/private/crt32/misc/alpha/divide2.s new file mode 100644 index 000000000..2eb50c2ba --- /dev/null +++ b/private/crt32/misc/alpha/divide2.s @@ -0,0 +1,1002 @@ +// TITLE("Fast Integer Division and Remainder") +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// divide2.s +// +// Abstract: +// +// This module implements high-performance versions of the integer divide +// and remainder routines that are called by assembler pseudo-ops. +// +// Author: +// +// Thomas Van Baak (tvb) 12-Jan-1993 +// Ken Lesniak (lesniak) 04-Nov-1992 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + +// +// Implementation Notes: +// +// There are no Alpha machine instructions for performing integer division +// (divl, divlu, divq, divqu) or remainder (reml, remlu, remq, remqu). The +// machine instructions generated for these assembler pseudo instructions +// are dependent on the type of operands. +// +// Division and remainder by constant values are replaced with a sequence +// of instructions that depend on the data type and the value of the +// constant. Shifting or reciprocal multiplication are used in most cases +// to generate the result. No run-time code is necessary in these cases. +// +// Division and remainder by non-constant values are replaced with a +// procedure call to a library routine to perform the operation. This file +// contains those routines. +// +// This code is adapted from the Alpha/OSF version by Ken Lesniak. +// +// There are two sets of these eight functions. The __div set were used +// by an earlier version of the acc compiler. This is the new __2div set. +// The new functions are about an order of magnitude faster. +// +// The new function names differ from the original set of functions so +// that the old and new compilers can co-exist for a time. +// +// Both the division algorithm code and the large division tables used by +// the code are contained in the fastdiv.s file which is included several +// times from this file. +// + +// +// Define common stack frame for functions in this file. +// + + .struct 0 +DvRa: .space 8 // save register ra +DvJr: .space 8 // save register t9 + +DvNu: .space 8 // save register t10 +DvDi: .space 8 // save register t11 + +DvT0: .space 8 // save register t0 +DvT1: .space 8 // save register t1 + +DvT2: .space 8 // save register t2 +DvT3: .space 8 // save register t3 + +DvT4: .space 8 // save register a0 + .space 8 // ensure 16-byte stack alignment +DvFrameLength: // length of stack frame + +// +// Define non-standard calling convention required by the compiler. +// +// The compiler uses t9, t10, t11, t12 as indicated below. All other +// registers (except AT) must be preserved by this calling convention. +// +// For the fastdiv code, since register a0 must be preserved anyway (it +// is used by gentrap), define temp register T4 to be a0. Similarly, +// register J4 must be preserved, so define temp register T5 to be Jr. +// And the fastdiv code allows Qu to also be temp register T6. +// + +#define Jr t9 // ($23) return address +#define Nu t10 // ($24) dividend (numerator) +#define Di t11 // ($25) divisor (denominator) +#define Qu t12 // ($27) result (quotient) +#define Re Qu // ($27) result (remainder) + +#define T0 t0 // standard temp +#define T1 t1 // standard temp +#define T2 t2 // standard temp +#define T3 t3 // standard temp +#define T4 a0 // may use a0 as temp +#define T5 Jr // may use Jr as temp +#define T6 Qu // may overload Qu as temp T6 only + +#ifdef DIV2_DEBUG + +// +// In order to debug locally, re-define some of the registers so that +// these functions can be called using a standard calling convention. +// + +#undef Jr +#define Jr ra // standard return address register +#undef Nu +#define Nu a0 // dividend argument in a0 +#undef Di +#define Di a1 // divisor argument in a1 +#undef Qu +#define Qu v0 // quotient result in v0 +#undef Re +#define Re v0 // remainder result in v0 +#undef T4 +#define T4 t4 // normal temp + +#endif + + SBTTL("Signed Long Integer Division") +//++ +// +// LONG +// __2divl ( +// IN LONG Dividend, +// IN LONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 32-bit integer by a signed 32-bit integer +// and returns the signed 32-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (quotient) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2divl, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + + addl Nu, 0, Nu // convert LONG dividend to quadword + addl Di, 0, Di // convert LONG divisor to quadword + +// +// Check for division of the most negative integer (0x800...00) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addl Di, 1, t0 // 0 if Di == -1; != 0 otherwise + mov Nu, t1 // copy dividend + cmovne t0, 0, t1 // replace w/ 0 if divisor != -1 + sublv zero, t1, t1 // trap if dividend == 0x800..00 + +// +// Convert negative arguments to positive for the division algorithm. +// + + subq zero, Nu, t0 // negate dividend + cmovlt Nu, t0, Nu // get absolute value of dividend + subq zero, Di, t0 // negate divisor + cmovlt Di, t0, Di // get absolute value of divisor + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | DIVISION) + +#include "fastdiv.s" + +// +// Restore some registers and set the correct sign of the quotient. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + addl Qu, 0, Qu // ensure quotient is in canonical form + subl zero, Qu, t1 // negate LONG quotient + xor Nu, Di, t0 // compute sign of quotient + addl t0, 0, t0 // ensure quotient is in canonical form + cmovlt t0, t1, Qu // use negated quotient if necessary + +// +// Restore other saved registers and return with quotient in register Qu. +// + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2divl + + SBTTL("Unsigned Long Integer Division") +//++ +// +// ULONG +// __2divlu ( +// IN ULONG Dividend, +// IN ULONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 32-bit integer by an unsigned 32-bit +// integer and returns the unsigned 32-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (quotient) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2divlu, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + + zap Nu, 0xf0, Nu // convert ULONG dividend to quadword + zap Di, 0xf0, Di // convert ULONG divisor to quadword + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | DIVISION) + +#include "fastdiv.s" + +// +// Restore all saved registers and return with quotient in register Qu. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2divlu + + SBTTL("Signed Quad Integer Division") +//++ +// +// LONGLONG +// __2divq ( +// IN LONGLONG Dividend, +// IN LONGLONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 64-bit integer by a signed 64-bit integer +// and returns the signed 64-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (quotient) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2divq, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + +// +// Check for division of the most negative integer (0x800..00) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addq Di, 1, t0 // 0 if Di == -1; != 0 otherwise + mov Nu, t1 // copy dividend + cmovne t0, 0, t1 // replace w/ 0 if divisor != -1 + subqv zero, t1, t1 // trap if dividend == 0x800..00 + +// +// Convert negative arguments to positive for the division algorithm. +// + + subq zero, Nu, t0 // negate dividend + cmovlt Nu, t0, Nu // get absolute value of dividend + subq zero, Di, t0 // negate divisor + cmovlt Di, t0, Di // get absolute value of divisor + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | DIVISION) + +#include "fastdiv.s" + +// +// Restore some registers and set the correct sign of the quotient. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + subq zero, Qu, t1 // negate quadword quotient + xor Nu, Di, t0 // compute sign of quotient + cmovlt t0, t1, Qu // use negated quotient if necessary + +// +// Restore other saved registers and return with quotient in register Qu. +// + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2divq + + SBTTL("Unsigned Quad Integer Division") +//++ +// +// ULONGLONG +// __2divqu ( +// IN ULONGLONG Dividend, +// IN ULONGLONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 64-bit integer by an unsigned 64-bit +// integer and returns the unsigned 64-bit integer result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (quotient) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2divqu, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | DIVISION) + +#include "fastdiv.s" + +// +// Restore all saved registers and return with quotient in register Qu. +// + + ldq Jr, DvJr(sp) // restore return address + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2divqu + + SBTTL("Signed Long Integer Remainder") +//++ +// +// LONG +// __2reml ( +// IN LONG Dividend, +// IN LONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 32-bit integer by a signed 32-bit integer +// and returns the signed 32-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (remainder) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2reml, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + + addl Nu, 0, Nu // convert LONG dividend to quadword + addl Di, 0, Di // convert LONG divisor to quadword + +// +// Check for division of the most negative integer (0x800..00) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addl Di, 1, t0 // 0 if Di == -1; != 0 otherwise + mov Nu, t1 // copy dividend + cmovne t0, 0, t1 // replace w/ 0 if divisor != -1 + sublv zero, t1, t1 // trap if dividend == 0x800..00 + +// +// Convert negative arguments to positive for the division algorithm. +// + + subq zero, Nu, t0 // negate dividend + cmovlt Nu, t0, Nu // get absolute value of dividend + subq zero, Di, t0 // negate divisor + cmovlt Di, t0, Di // get absolute value of divisor + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | REMAINDER) + +#include "fastdiv.s" + +// +// Restore some registers and set the correct sign of the remainder. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + addl Qu, 0, Qu // ensure remainder is in canonical form + subl zero, Qu, t1 // negate LONG remainder + addl Nu, 0, t0 // get dividend in canonical form + cmovlt t0, t1, Qu // use negated remainder if necessary + +// +// Restore other saved registers and return with remainder in register Qu. +// + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2reml + + SBTTL("Unsigned Long Integer Remainder") +//++ +// +// ULONG +// __2remlu ( +// IN ULONG Dividend, +// IN ULONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 32-bit integer by an unsigned 32-bit +// integer and returns the unsigned 32-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 32-bit integer result (remainder) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2remlu, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + + zap Nu, 0xf0, Nu // convert ULONG dividend to quadword + zap Di, 0xf0, Di // convert ULONG divisor to quadword + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | REMAINDER) + +#include "fastdiv.s" + +// +// Restore all saved registers and return with remainder in register Qu. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2remlu + + SBTTL("Signed Quad Integer Remainder") +//++ +// +// LONGLONG +// __2remq ( +// IN LONGLONG Dividend, +// IN LONGLONG Divisor +// ) +// +// Routine Description: +// +// This function divides a signed 64-bit integer by a signed 64-bit integer +// and returns the signed 64-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (remainder) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2remq, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq Nu, DvNu(sp) // save original dividend + stq Di, DvDi(sp) // save original divisor + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + +// +// Check for division of the most negative integer (0x800..00) by the least +// negative (-1). The result would be an integer which is one greater than the +// maximum positive integer. Since this cannot be represented, an overflow must +// be generated. +// + + addq Di, 1, t0 // 0 if Di == -1; != 0 otherwise + mov Nu, t1 // copy dividend + cmovne t0, 0, t1 // replace w/ 0 if divisor != -1 + subqv zero, t1, t1 // trap if dividend == 0x800..00 + +// +// Convert negative arguments to positive for the division algorithm. +// + + subq zero, Nu, t0 // negate dividend + cmovlt Nu, t0, Nu // get absolute value of dividend + subq zero, Di, t0 // negate divisor + cmovlt Di, t0, Di // get absolute value of divisor + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | REMAINDER) + +#include "fastdiv.s" + +// +// Restore some registers and set the correct sign of the remainder. +// + + ldq Jr, DvJr(sp) // restore return address + ldq Nu, DvNu(sp) // restore original dividend + ldq Di, DvDi(sp) // restore original divisor + + subq zero, Qu, t1 // negate quadword remainder + cmovlt Nu, t1, Qu // use negated remainder if necessary + +// +// Restore other saved registers and return with remainder in register Qu. +// + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2remq + + SBTTL("Unsigned Quad Integer Remainder") +//++ +// +// ULONGLONG +// __2remqu ( +// IN ULONGLONG Dividend, +// IN ULONGLONG Divisor +// ) +// +// Routine Description: +// +// This function divides an unsigned 64-bit integer by an unsigned 64-bit +// integer and returns the unsigned 64-bit integer remainder result. +// +// Arguments: +// +// Dividend (t10) - Supplies the dividend (numerator) value. +// +// Divisor (t11) - Supplies the divisor (denominator) value. +// +// Return Value: +// +// The 64-bit integer result (remainder) is returned in register t12. +// +// Note: +// +// This function uses a non-standard calling procedure. The return address +// is stored in the t9 register and the return value is in the t10 register. +// No other registers are modified. +// +//-- + + NESTED_ENTRY(__2remqu, DvFrameLength, Jr) + +// +// This prologue is magic. When executed during a call, it will save the +// value of register ra (twice) and register t9 in the stack frame, even +// though these registers are not modified by this function. The stores +// appear to unnecessary. +// +// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue +// is reverse executed by virtual unwind to reset the stack pointer and to +// obtain the return address. The return address is the value of RA the +// first time it is restored, which will be the saved value of t9. +// + + .set noreorder + .set noat + lda sp, -DvFrameLength(sp) // allocate stack frame + + stq ra, DvRa(sp) // save ra register + stq ra, DvJr(sp) // backtrace return address + stq Jr, DvJr(sp) // save actual return address + + stq t0, DvT0(sp) // save temp registers + stq t1, DvT1(sp) // + stq t2, DvT2(sp) // + stq t3, DvT3(sp) // + stq T4, DvT4(sp) // + .set at + .set reorder + + PROLOGUE_END + +// +// Set up defines and include the main body of the division code. +// + +#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | REMAINDER) + +#include "fastdiv.s" + +// +// Restore all saved registers and return with remainder in register Qu. +// + + ldq Jr, DvJr(sp) // restore return address + + ldq t0, DvT0(sp) // restore temp registers + ldq t1, DvT1(sp) // + ldq t2, DvT2(sp) // + ldq t3, DvT3(sp) // + ldq T4, DvT4(sp) // + + lda sp, DvFrameLength(sp) // deallocate stack frame + ret zero, (Jr) // return + + .end __2remqu + +// +// Now get one copy of the tables needed by the division code. +// + +#define FASTDIV_TABLES + +#include "fastdiv.s" diff --git a/private/crt32/misc/alpha/extv.s b/private/crt32/misc/alpha/extv.s new file mode 100644 index 000000000..bd7e1b754 --- /dev/null +++ b/private/crt32/misc/alpha/extv.s @@ -0,0 +1,82 @@ + #++ + # Copyright 1991, Digital Equipment Corporation + # + # int ots_extv(char *addr, int position, unsigned size) + # + # Arbitrary signed bitfield extraction + # + # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_extv (just uses srl in place of sra in some cases...) + # + # 001 16 Aug 1991 KDG Initial version + # + # 002 4 Sep 1991 KDG Bugfix/improvements + # + # 003 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 004 22 Sep 1992 KDG Case-sensitive name + # + # 005 26 Jan 1993 KDG Add underscore + +#include "ots_defs.hs" + + # Totally general field extract - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # + # This is based on the code GEM generates when not using an out-of-line + # routine. + # + .globl _OtsFieldExtractSigned + .ent _OtsFieldExtractSigned +_OtsFieldExtractSigned: + .set noat + .set noreorder + .frame sp,0,r26 + sra r17, 3, r27 # get byte part of bit offset (signed!) + ble r18, zero # check for zero size - no memory access + addq r16, r27, r16 # add to initial base addr. + ldq_u r0, (r16) # start load first or only quadword + and r16, 7, r27 # get byte-in-quadword of first bit + and r17, 7, r17 # get bit-in-byte from bit offset + s8addq r27, r17, r17 # form the true bit offset in the quadword + addq r17, r18, r27 # get bit offset of bit following field + cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword + beq r28, double # handle double case if not + # common case - fall through, load result hopefully already available +single: negq r27, r27 # <5:0> = bits for right shift + sll r0, r27, r0 # move to high bits + addq r27, r17, r27 # bits for left shift + sra r0, r27, r0 # and shift into final position + ret r31, (r26) +double: ldq_u r28, 8(r16) # load second quadword + srl r0, r27, r0 # move top piece over + negq r27, r27 # get shift bits for piece in 2nd word + sll r28, r27, r28 # move field in 2nd lw to high bits + bis r0, r28, r0 # form final value + negq r18, r27 # <5:0> = bits for right shift + sra r0, r27, r0 # and shift into final position + ret r31, (r26) +zero: mov 0, r0 # zero-sized field extracts return 0 + ret r31, (r26) + + .set at + .set reorder + .end _OtsFieldExtractSigned diff --git a/private/crt32/misc/alpha/extvvol.s b/private/crt32/misc/alpha/extvvol.s new file mode 100644 index 000000000..f64dfa2a2 --- /dev/null +++ b/private/crt32/misc/alpha/extvvol.s @@ -0,0 +1,98 @@ + #++ + # Copyright 1992, Digital Equipment Corporation + # + # int ots_extv_vol(char *addr, int position, unsigned size) + # + # Arbitrary signed bitfield extraction for volatile cases + # + # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_extv_vol (just uses srl in place of sra in some cases...) + # + # 001 16 Aug 1991 KDG Initial version + # + # 002 4 Sep 1991 KDG Bugfix/improvements + # + # 003 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 004 6 Oct 1992 KDG Initial volatile version (just add longword + # test) + # + # 005 10 Nov 1992 KDG Case-sensitive name + # + # 006 26 Jan 1993 KDG Add underscore + # + # 007 1 Sep 1994 RBG Fix aligned longword case + # check for bit 0 within byte GEM_BUGS #3545 + +#include "ots_defs.hs" + + # Totally general field extract - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. + # + # This volatile version always uses exactly LDL for aligned 32 bit field + # extracts, and quadword operations for all other. + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # + # This is based on the code GEM generates when not using an out-of-line + # routine. + # + .globl _OtsFieldExtractSignedVolatile + .ent _OtsFieldExtractSignedVolatile +_OtsFieldExtractSignedVolatile: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + sra r17, 3, r27 # get byte part of bit offset (signed!) + ble r18, zero # check for zero size - no memory access + cmpeq r17, 32, r0 # exactly longword size? + addq r16, r27, r16 # add to initial base addr. + and r16, 3, r28 # aligned longword? + cmpult r28, r0, r28 # true if ((addr & 3) == 0) && (size == 32) && ... + and r17, 7, r17 # get bit-in-byte from bit offset + cmpult r17, r28, r28 # ... && (bit_in_byte == 0) + bne r28, longwd # go handle longword case specially + ldq_u r0, (r16) # start load first or only quadword + and r16, 7, r27 # get byte-in-quadword of first bit + s8addq r27, r17, r17 # form the true bit offset in the quadword + addq r17, r18, r27 # get bit offset of bit following field + cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword + beq r28, double # handle double case if not + # common case - fall through, load result hopefully already available +single: negq r27, r27 # <5:0> = bits for right shift + sll r0, r27, r0 # move to high bits + addq r27, r17, r27 # bits for left shift + sra r0, r27, r0 # and shift into final position + ret r31, (r26) +double: ldq_u r28, 8(r16) # load second quadword + srl r0, r27, r0 # move top piece over + negq r27, r27 # get shift bits for piece in 2nd word + sll r28, r27, r28 # move field in 2nd lw to high bits + bis r0, r28, r0 # form final value + negq r18, r27 # <5:0> = bits for right shift + sra r0, r27, r0 # and shift into final position + ret r31, (r26) +zero: mov 0, r0 # zero-sized field extracts return 0 + ret r31, (r26) +longwd: ldl r0, (r16) # load sign-extended aligned longword + ret r31, (r26) + .set at + .set reorder + .end _OtsFieldExtractSignedVolatile diff --git a/private/crt32/misc/alpha/extzv.s b/private/crt32/misc/alpha/extzv.s new file mode 100644 index 000000000..fb73dfb8e --- /dev/null +++ b/private/crt32/misc/alpha/extzv.s @@ -0,0 +1,83 @@ + #++ + # Copyright 1991, Digital Equipment Corporation + # + # int ots_extzv(char *addr, int position, unsigned size) + # + # Arbitrary unsigned bitfield extraction + # + # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_extv (just uses sra in place of srl in some cases...) + # + # 001 16 Aug 1991 KDG Initial version + # + # 002 4 Sep 1991 KDG Bugfix/improvements + # + # 003 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 004 22 Sep 1992 KDG Add case-sensitive name + # + # 005 26 Jan 1993 KDG Add underscore + +#include "ots_defs.hs" + + # + # Totally general field extract - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # + # This is based on the code GEM generates when not using an out-of-line + # routine. + # + .globl _OtsFieldExtractUnsigned + .ent _OtsFieldExtractUnsigned +_OtsFieldExtractUnsigned: + .set noat + .set noreorder + .frame sp,0,r26 + sra r17, 3, r27 # get byte part of bit offset (signed!) + ble r18, zero # check for zero size - no memory access + addq r16, r27, r16 # add to initial base addr. + ldq_u r0, (r16) # start load first or only quadword + and r16, 7, r27 # get byte-in-quadword of first bit + and r17, 7, r17 # get bit-in-byte from bit offset + s8addq r27, r17, r17 # form the true bit offset in the quadword + addq r17, r18, r27 # get bit offset of bit following field + cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword + beq r28, double # handle double case if not + # common case - fall through, load result hopefully already available +single: negq r27, r27 # <5:0> = bits for right shift + sll r0, r27, r0 # move to high bits + addq r27, r17, r27 # bits for left shift + srl r0, r27, r0 # and shift into final position + ret r31, (r26) +double: ldq_u r28, 8(r16) # load second quadword + srl r0, r27, r0 # move top piece over + negq r27, r27 # get shift bits for piece in 2nd word + sll r28, r27, r28 # move field in 2nd lw to high bits + bis r0, r28, r0 # form final value + negq r18, r27 # <5:0> = bits for right shift + srl r0, r27, r0 # and shift into final position + ret r31, (r26) +zero: mov 0, r0 # zero-sized field extracts return 0 + ret r31, (r26) + + .set at + .set reorder + .end _OtsFieldExtractUnsigned diff --git a/private/crt32/misc/alpha/extzvvol.s b/private/crt32/misc/alpha/extzvvol.s new file mode 100644 index 000000000..7d3969561 --- /dev/null +++ b/private/crt32/misc/alpha/extzvvol.s @@ -0,0 +1,101 @@ + #++ + # Copyright 1991, Digital Equipment Corporation + # + # int ots_extzv_vol(char *addr, int position, unsigned size) + # + # Arbitrary unsigned bitfield extraction for volatile cases + # + # Special conventions: No stack space, r0, r16-r18 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_extv_vol (just uses sra in place of srl in some cases...) + # + # 001 16 Aug 1991 KDG Initial version + # + # 002 4 Sep 1991 KDG Bugfix/improvements + # + # 003 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 004 6 Oct 1992 KDG Initial volatile version (just add longword + # test) + # + # 005 10 Oct 1992 KDG Case-sensitive name + # + # 006 26 Jan 1993 KDG Add underscore + # + # 007 1 Sep 1994 RBG Fix aligned longword case + # check for bit 0 within byte GEM_BUGS #3545 + +#include "ots_defs.hs" + + # + # Totally general field extract - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. + # + # This volatile version always uses exactly LDL for aligned 32 bit field + # extracts, and quadword operations for all other. + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # + # This is based on the code GEM generates when not using an out-of-line + # routine. + # + .globl _OtsFieldExtractUnsignedVolatile + .ent _OtsFieldExtractUnsignedVolatile +_OtsFieldExtractUnsignedVolatile: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + sra r17, 3, r27 # get byte part of bit offset (signed!) + ble r18, zero # check for zero size - no memory access + cmpeq r17, 32, r0 # exactly longword size? + addq r16, r27, r16 # add to initial base addr. + and r16, 3, r28 # aligned longword? + cmpult r28, r0, r28 # true if ((addr & 3) == 0) && (size == 32) && ... + and r17, 7, r17 # get bit-in-byte from bit offset + cmpult r17, r28, r28 # ... && (bit_in_byte == 0) + bne r28, longwd # go handle longword case specially + ldq_u r0, (r16) # start load first or only quadword + and r16, 7, r27 # get byte-in-quadword of first bit + s8addq r27, r17, r17 # form the true bit offset in the quadword + addq r17, r18, r27 # get bit offset of bit following field + cmpule r27, 64, r28 # if <=64, field is contained in 1 quadword + beq r28, double # handle double case if not + # common case - fall through, load result hopefully already available +single: negq r27, r27 # <5:0> = bits for right shift + sll r0, r27, r0 # move to high bits + addq r27, r17, r27 # bits for left shift + srl r0, r27, r0 # and shift into final position + ret r31, (r26) +double: ldq_u r28, 8(r16) # load second quadword + srl r0, r27, r0 # move top piece over + negq r27, r27 # get shift bits for piece in 2nd word + sll r28, r27, r28 # move field in 2nd lw to high bits + bis r0, r28, r0 # form final value + negq r18, r27 # <5:0> = bits for right shift + srl r0, r27, r0 # and shift into final position + ret r31, (r26) +zero: mov 0, r0 # zero-sized field extracts return 0 + ret r31, (r26) +longwd: ldl r0, (r16) # load sign-extended aligned longword + zapnot r0, 15, r0 + ret r31, (r26) + + .set at + .set reorder + .end _OtsFieldExtractUnsignedVolatile diff --git a/private/crt32/misc/alpha/fastdiv.s b/private/crt32/misc/alpha/fastdiv.s new file mode 100644 index 000000000..600c89ef9 --- /dev/null +++ b/private/crt32/misc/alpha/fastdiv.s @@ -0,0 +1,662 @@ +// TITLE("High-Performance Division") +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// fastdiv.s +// +// Abstract: +// +// This module implements a high-performance integer division routine +// whose source is included from each of the division and remainder +// functions. +// +// Author: +// +// Thomas Van Baak (tvb) 12-Jan-1993 +// Ken Lesniak (lesniak) 04-Nov-1992 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +// +// Implementation Notes: +// +// This code is the main "guts" of the eight divide and remainder routines +// in the C library. It is intended to be included by a wrapper function +// that defines options to control 32 vs. 64-bit, division vs. remainder, +// and signed vs. unsigned. The wrapper function is responsible for the +// prologue and epilogue sequences, as well as overflow checking and sign +// adjustment on both input arguments and the return value. +// +// The algorithm used here is based on long division and a table for +// approximating inverses as discussed in the paper "Division by a Constant" +// by Mary Payne and Robert Gries. If the divisor inverse can be constructed +// from the table without an error, the division is performed as described +// in the paper with a multiplication and a shift. +// +// If the inverse can not be found in the table, we improve the inverse with +// a linear approximation, "I". A multiplication by "I" and a shift by +// log2(y) is used to obtain an approximate quotient, "Q". Now, like long +// division, the most significant bits are correct, therefore if we +// calculate the remainder R = x-Q*y, R will be smaller than x, and R will +// contain the true remainder and the error in Q, "e" multiplied by y. +// +// So if we do the same multiplication and shift, we will get an +// approximation for e. This is just long division, and it will finish +// when R, the remainder, is less than y. +// +// Both the division algorithm code and the large division tables used by +// the code are contained in this source file (to keep them together). +// + +// +// The code below requires that the wrapper function define register numbers +// for each of the following symbolic register names: +// +// Nu dividend (numerator) +// Di divisor (denominator) +// Qu quotient +// Re remainder (may be the same as Qu) +// +// T0 temp +// T1 temp +// T2 temp +// T3 temp +// T4 temp +// T5 temp +// T6 temp (may be shared with Qu) +// + +// +// The code below requires that the wrapper function define the symbol +// FASTDIV_OPTIONS as the logical sum of the following names: +// + +#define THIRTY_TWO_BIT 1 // perform 32-bit computations, otherwise +#define SIXTY_FOUR_BIT 0 // perform 64-bit computations + +#define UNSIGNED 2 // treat operands as unsigned, otherwise +#define SIGNED 0 // treat operands as signed + +#define DIVISION 4 // return quotient in Qu register, and/or +#define REMAINDER 8 // return remainder in Re register + +// +// Define the symbols that actually control the code generation. +// + +#define _THIRTYTWOBIT (FASTDIV_OPTIONS & THIRTY_TWO_BIT) +#define _SIXTYFOURBIT (!(FASTDIV_OPTIONS & THIRTY_TWO_BIT)) +#define _UNSIGNED (FASTDIV_OPTIONS & UNSIGNED) +#define _REMAINDER (FASTDIV_OPTIONS & REMAINDER) +#define _QUOTIENT (FASTDIV_OPTIONS & DIVISION) + +// +// These constants give the algorithm the best performance. +// + +#define BIT_LENGTH 8 +#define BIT_VALUE (1 << BIT_LENGTH) +#define BIT_MASK (BIT_VALUE - 1) + +#define K_BIT_LENGTH 8 +#define K_BIT_VALUE (1 << K_BIT_LENGTH) +#define K_BIT_MASK (K_BIT_VALUE - 1) + +#define TABLE_BIAS 16384 + +#define LOG2TAB -16384 +#define INV_FLAG -15360 +#define INV -14848 +#define INV_M -14840 + +#ifndef FASTDIV_TABLES + + .set noat + + lda T3, __2divdata + TABLE_BIAS // set address of table + beq Di, 30f // if zero divisor, generate trap + + cmpule Nu, Di, T0 // check if dividend <= divisor +#if _THIRTYTWOBIT + addl Di, 0, T1 // sign extend longword to quadword + blt T1, 20f // high bit set so quotient <= 1 +#endif +#if _SIXTYFOURBIT + blt Di, 20f // high bit set so quotient <= 1 +#endif + + cmpbge zero, Di, T2 // perform 8 byte parallel compare + bne T0, 20f // dividend <= divisor so quotient <= 1 + + xor T2, 0xff, T0 // + s4addq T0, T3, T0 // + ldl AT, LOG2TAB(T0) // + extbl Di, AT, T0 // + s4addq T0, T3, T0 // + ldl T0, LOG2TAB(T0) // + s8addq AT, T0, AT // + ornot zero, AT, T0 // + sll Di, T0, T0 // + sll T0, BIT_LENGTH + 1, T1 // + bne T1, 40f // + +// +// Short case. +// + + subq Di, 1, T1 // compute divisor - 1 + and Di, T1, T2 // divisor & (divisor - 1) + srl T0, 63 - (BIT_LENGTH + 1), T6 // + beq T2, 10f // divisor is a power of two + + subq T6, BIT_VALUE + BIT_VALUE, T6 // + bic T6, 1, T4 // + s8addq T4, T3, T4 // + ldq T5, INV(T4) // + ldq T4, INV_M(T4) // + subq T5, T4, T4 // + cmovlbs T6, T4, T5 // + addq T6, T3, T2 // + ldq_u T0, INV_FLAG(T2) // + extbl T0, T2, T2 // + addq Nu, T2, T1 // + umulh T1, T5, T3 // +#if _SIXTYFOURBIT && _UNSIGNED + cmoveq T1, T5, T3 // +#endif + srl T3, AT, Qu // +#if _REMAINDER + mulq Qu, Di, T0 // + subq Nu, T0, Re // +#endif + br zero, 90f // all done, branch to epilogue code + +10: + +// +// The divisor is now known to be a power of two. +// +// - The quotient is the dividend shifted right by exponent bits and +// the remainder is the low order exponent bits of the dividend. +// +// AT = log2(divisor) +// T1 = divisor - 1 +// + +#if _REMAINDER + and Nu, T1, Re // +#endif +#if _QUOTIENT + srl Nu, AT, Qu // +#endif + br zero, 90f // all done, branch to epilogue code + +20: + +// +// The quotient is now known to be either 0 or 1. +// +// - if the high bit of the divisor is set, the quotient must be less +// than 2, so the quotient is 0 or 1. +// +// - if the dividend is less than the divisor, the quotient is 0 and +// the remainder is the dividend. +// +// - if the dividend is equal to the divisor, the quotient is 1 and +// the remainder is 0. +// +// - if the dividend is greater than the divisor, the quotient is 1 +// and the remainder is the dividend minus the divisor. +// + +#if _REMAINDER + cmpule Di, Nu, T0 // if divisor <= dividend + subq Nu, Di, Re // then remainder is dividend, + cmoveq T0, Nu, Re // else remainder is dividend - divisor +#endif +#if _QUOTIENT + cmpule Di, Nu, Qu // if divisor <= dividend, 1, else 0 +#endif + br zero, 90f // all done, branch to epilogue code + +// +// Generate divide by zero exception. If execution is continued, return +// a zero result. +// + +30: ldiq a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO + + GENERATE_TRAP + + ldiq Qu, 0 // supply 0 result if continued + br zero, 90f // branch to epilogue code + +// +// Long case. +// + +40: srl T0, 63-(BIT_LENGTH+K_BIT_LENGTH), T6 // + srl T6, K_BIT_LENGTH, T0 // + and T6, K_BIT_MASK, T6 // + addq T0, T0, T0 // + s8addq T0, T3, T1 // + ldq T2, INV-(16*BIT_VALUE)(T1) // + ldq T0, INV_M-(16*BIT_VALUE)(T1) // + mulq T0, T6, T0 // + srl T0, K_BIT_LENGTH-1, T0 // + subq T2, T0, T6 // + umulh Nu, T6, T4 // + srl T4, AT, T4 // + mulq T4, Di, T5 // + mov zero, T3 // +#if _SIXTYFOURBIT + xor Nu, T5, T0 // + bge T0, 50f // + + umulh Di, T4, T3 // +50: +#endif + subq Nu, T5, T5 // + beq T4, 70f // + + cmpult Nu, T5, T0 // + or T0, T3, T3 // + negq T5, T1 // + cmovne T3, T1, T5 // + addq Di, Di, T0 // + cmpule T0, T5, T0 // + beq T0, 70f // + +// +// do { +// + +60: umulh T5, T6, T2 // + srl T2, AT, T2 // + negq T2, T0 // + cmoveq T3, T2, T0 // + addq T4, T0, T4 // + mulq T2, Di, T1 // + subq T5, T1, T5 // +#if _SIXTYFOURBIT + ldiq T0, 1 // + cmovne T3, 0, T0 // + negq T5, T2 // + cmovlt T5, T0, T3 // + cmovlt T5, T2, T5 // +#endif + addq Di, Di, T0 // + cmpule T5, T0, T0 // + cmovne T0, 0, T1 // + bne T1, 60b // + +// +// } while +// + +70: cmpule Di, T5, T0 // + beq T0, 80f // + + subq T5, Di, T5 // + subq T4, 1, T0 // + addq T4, 1, T4 // + cmovne T3, T0, T4 // +80: + cmoveq T5, 0, T3 // +#if _REMAINDER + subq Di, T5, Re // + cmoveq T3, T5, Re // +#endif +#if _QUOTIENT + subq T4, 1, Qu // + cmoveq T3, T4, Qu // +#endif + +90: + .set at + +#undef FASTDIV_OPTIONS + +#else + +// +// The following data was machine generated. DO NOT EDIT MANUALLY. +// + + .globl __2divdata + .rdata + .align 4 +__2divdata: + +// +// LOG2TAB +// + + .align 2 + .long 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .long 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + .long 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .long 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 + .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 + .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 + .long 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .long 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + +// +// INV_FLAG +// + + .align 3 + .byte 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1 + .byte 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0 + .byte 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1 + .byte 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0 + .byte 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0 + .byte 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 + .byte 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1 + .byte 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0 + .byte 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1 + .byte 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1 + .byte 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1 + .byte 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1 + .byte 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1 + .byte 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0 + .byte 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1 + .byte 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 + .byte 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 + .byte 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 + .byte 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1 + .byte 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0 + .byte 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1 + .byte 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 + .byte 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 + .byte 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 + .byte 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1 + .byte 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0 + .byte 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1 + .byte 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1 + .byte 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 + .byte 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 + .byte 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1 + .byte 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1 + +// +// INV INV_M +// + + .align 4 + .quad 0xffffffffffffffff, 0x007fc01ff007fc01, // 0 + .quad 0xff00ff00ff00ff01, 0x007ec25bf68dabfe, // 1 + .quad 0xfe03f80fe03f80fe, 0x007dc78930f5b971, // 2 + .quad 0xfd08e5500fd08e55, 0x007ccf9c05f3157c, // 3 + .quad 0xfc0fc0fc0fc0fc10, 0x007bda891528a983, // 4 + .quad 0xfb18856506ddaba6, 0x007ae84535db391c, // 5 + .quad 0xfa232cf252138ac0, 0x0079f8c575ac2ab0, // 6 + .quad 0xf92fb2211855a865, 0x00790bff175cf1bf, // 7 + .quad 0xf83e0f83e0f83e10, 0x007821e7919ad7f4, // 8 + .quad 0xf74e3fc22c700f75, 0x00773a748dd2e48d, // 9 + .quad 0xf6603d980f6603da, 0x0076559be70da3cb, // 10 + .quad 0xf57403d5d00f5740, 0x00757353a8d2921b, // 11 + .quad 0xf4898d5f85bb3950, 0x007493920e12f0da, // 12 + .quad 0xf3a0d52cba872336, 0x0073b64d801bcc4b, // 13 + .quad 0xf2b9d6480f2b9d65, 0x0072db7c958efc82, // 14 + .quad 0xf1d48bcee0d399fa, 0x007203161162ec7b, // 15 + .quad 0xf0f0f0f0f0f0f0f1, 0x00712d10e1e8f4b3, // 16 + .quad 0xf00f00f00f00f00f, 0x007059641fda17d7, // 17 + .quad 0xef2eb71fc4345238, 0x006f88070d69f229, // 18 + .quad 0xee500ee500ee500f, 0x006eb8f1155fad72, // 19 + .quad 0xed7303b5cc0ed730, 0x006dec19ca34cd01, // 20 + .quad 0xec979118f3fc4da2, 0x006d2178e539a6a8, // 21 + .quad 0xebbdb2a5c1619c8c, 0x006c590645bf5ef6, // 22 + .quad 0xeae56403ab95900f, 0x006b92b9f0474060, // 23 + .quad 0xea0ea0ea0ea0ea0f, 0x006ace8c0db7463d, // 24 + .quad 0xe939651fe2d8d35c, 0x006a0c74ea93b5ce, // 25 + .quad 0xe865ac7b7603a197, 0x00694c6cf63da0af, // 26 + .quad 0xe79372e225fe30d9, 0x00688e6cc2362d3c, // 27 + .quad 0xe6c2b4481cd85689, 0x0067d26d016682a0, // 28 + .quad 0xe5f36cb00e5f36cb, 0x00671866876c373e, // 29 + .quad 0xe525982af70c880e, 0x0066605247ea214c, // 30 + .quad 0xe45932d7dc52100e, 0x0065aa2955dd6a6f, // 31 + .quad 0xe38e38e38e38e38e, 0x0064f5e4e2f6c80c, // 32 + .quad 0xe2c4a6886a4c2e10, 0x0064437e3ef7bb1b, // 33 + .quad 0xe1fc780e1fc780e2, 0x006392eed713bb0b, // 34 + .quad 0xe135a9c97500e136, 0x0062e43035553040, // 35 + .quad 0xe070381c0e070382, 0x0062373c00062374, // 36 + .quad 0xdfac1f74346c575f, 0x00618c0bf91c8837, // 37 + .quad 0xdee95c4ca037ba57, 0x0060e299fdaa0972, // 38 + .quad 0xde27eb2c41f3d9d1, 0x00603ae0054f3f9c, // 39 + .quad 0xdd67c8a60dd67c8a, 0x005f94d821b23932, // 40 + .quad 0xdca8f158c7f91ab8, 0x005ef07c7df83e6e, // 41 + .quad 0xdbeb61eed19c5958, 0x005e4dc75e42ba41, // 42 + .quad 0xdb2f171df7702919, 0x005dacb31f2f32ed, // 43 + .quad 0xda740da740da740e, 0x005d0d3a355a3d88, // 44 + .quad 0xd9ba4256c0366e91, 0x005c6f572ce55811, // 45 + .quad 0xd901b2036406c80e, 0x005bd304a8ff968c, // 46 + .quad 0xd84a598ec9151f43, 0x005b383d63711014, // 47 + .quad 0xd79435e50d79435e, 0x005a9efc2c28f962, // 48 + .quad 0xd6df43fca482f00d, 0x005a073be8ce5ae4, // 49 + .quad 0xd62b80d62b80d62c, 0x005970f7945350f4, // 50 + .quad 0xd578e97c3f5fe551, 0x0058dc2a3e8ac544, // 51 + .quad 0xd4c77b03531dec0d, 0x005848cf0bc0912f, // 52 + .quad 0xd4173289870ac52e, 0x0057b6e13453f8e0, // 53 + .quad 0xd3680d3680d3680d, 0x0057265c04546fe2, // 54 + .quad 0xd2ba083b445250ab, 0x0056973adb20982b, // 55 + .quad 0xd20d20d20d20d20d, 0x005609792b076ce1, // 56 + .quad 0xd161543e28e50274, 0x00557d1278eb8ad3, // 57 + .quad 0xd0b69fcbd2580d0b, 0x0054f2025be888c5, // 58 + .quad 0xd00d00d00d00d00d, 0x005468447cfa5248, // 59 + .quad 0xcf6474a8819ec8e9, 0x0053dfd496a67807, // 60 + .quad 0xcebcf8bb5b4169cb, 0x005358ae74a768fd, // 61 + .quad 0xce168a7725080ce1, 0x0052d2cdf3998842, // 62 + .quad 0xcd712752a886d242, 0x00524e2f00aa138f, // 63 + .quad 0xcccccccccccccccd, 0x0051cacd9947cecc, // 64 + .quad 0xcc29786c7607f99f, 0x005148a5cad5697f, // 65 + .quad 0xcb8727c065c393e0, 0x0050c7b3b25d9315, // 66 + .quad 0xcae5d85f1bbd6c95, 0x005047f37c48b368, // 67 + .quad 0xca4587e6b74f0329, 0x004fc96164143d25, // 68 + .quad 0xc9a633fcd967300d, 0x004f4bf9b40b9000, // 69 + .quad 0xc907da4e871146ad, 0x004ecfb8c50260f1, // 70 + .quad 0xc86a78900c86a789, 0x004e549afe109ef0, // 71 + .quad 0xc7ce0c7ce0c7ce0c, 0x004dda9cd44fcaee, // 72 + .quad 0xc73293d789b9f838, 0x004d61baca99ba10, // 73 + .quad 0xc6980c6980c6980c, 0x004ce9f17148b95b, // 74 + .quad 0xc5fe740317f9d00c, 0x004c733d65f90a5a, // 75 + .quad 0xc565c87b5f9d4d1c, 0x004bfd9b534bb06e, // 76 + .quad 0xc4ce07b00c4ce07b, 0x004b8907f0aa86ab, // 77 + .quad 0xc4372f855d824ca6, 0x004b1580020d9680, // 78 + .quad 0xc3a13de60495c773, 0x004aa30057c1a767, // 79 + .quad 0xc30c30c30c30c30c, 0x004a3185ce30004a, // 80 + .quad 0xc2780613c0309e02, 0x0049c10d4da7534b, // 81 + .quad 0xc1e4bbd595f6e947, 0x00495193ca25cceb, // 82 + .quad 0xc152500c152500c1, 0x0048e31643243fb8, // 83 + .quad 0xc0c0c0c0c0c0c0c1, 0x00487591c36265c8, // 84 + .quad 0xc0300c0300c0300c, 0x0048090360b4318c, // 85 + .quad 0xbfa02fe80bfa02ff, 0x00479d683bd0279f, // 86 + .quad 0xbf112a8ad278e8dd, 0x004732bd801ebb67, // 87 + .quad 0xbe82fa0be82fa0bf, 0x0046c900638aa88c, // 88 + .quad 0xbdf59c91700bdf5a, 0x0046602e26524361, // 89 + .quad 0xbd69104707661aa3, 0x0045f84412d9ba97, // 90 + .quad 0xbcdd535db1cc5b7b, 0x0045913f7d7e44a5, // 91 + .quad 0xbc52640bc52640bc, 0x00452b1dc46a3383, // 92 + .quad 0xbbc8408cd63069a1, 0x0044c5dc4f69e972, // 93 + .quad 0xbb3ee721a54d880c, 0x004461788fc1a9a5, // 94 + .quad 0xbab656100bab6561, 0x0043fdf000043fdf, // 95 + .quad 0xba2e8ba2e8ba2e8c, 0x00439b4023ea7a13, // 96 + .quad 0xb9a7862a0ff46588, 0x00433966882b6f4f, // 97 + .quad 0xb92143fa36f5e02e, 0x0042d860c2558f4d, // 98 + .quad 0xb89bc36ce3e0453a, 0x0042782c70a87632, // 99 + .quad 0xb81702e05c0b8170, 0x004218c739ef8000, // 100 + .quad 0xb79300b79300b793, 0x0041ba2ecd5d1788, // 101 + .quad 0xb70fbb5a19be3659, 0x00415c60e266bc99, // 102 + .quad 0xb68d31340e4307d8, 0x0040ff5b38a1bd6e, // 103 + .quad 0xb60b60b60b60b60b, 0x0040a31b97a09f52, // 104 + .quad 0xb58a485518d1e7e4, 0x0040479fced1329a, // 105 + .quad 0xb509e68a9b94821f, 0x003fece5b55b4e37, // 106 + .quad 0xb48a39d44685fe97, 0x003f92eb2a002f2f, // 107 + .quad 0xb40b40b40b40b40b, 0x003f39ae12fa7858, // 108 + .quad 0xb38cf9b00b38cf9b, 0x003ee12c5ddecee8, // 109 + .quad 0xb30f63528917c80b, 0x003e8963ff7d1056, // 110 + .quad 0xb2927c29da5519cf, 0x003e3252f3c21e56, // 111 + .quad 0xb21642c8590b2164, 0x003ddbf73d9a3d87, // 112 + .quad 0xb19ab5c45606f00b, 0x003d864ee6d403ca, // 113 + .quad 0xb11fd3b80b11fd3c, 0x003d31580003d316, // 114 + .quad 0xb0a59b418d749d53, 0x003cdd10a067ddc1, // 115 + .quad 0xb02c0b02c0b02c0b, 0x003c8976e5ccb15f, // 116 + .quad 0xafb321a1496fdf0e, 0x003c3688f472452e, // 117 + .quad 0xaf3addc680af3ade, 0x003be444f6f1897b, // 118 + .quad 0xaec33e1f671529a5, 0x003b92a91e2274fb, // 119 + .quad 0xae4c415c9882b931, 0x003b41b3a1028dad, // 120 + .quad 0xadd5e6323fd48a86, 0x003af162bc9bea7b, // 121 + .quad 0xad602b580ad602b6, 0x003aa1b4b3ecab20, // 122 + .quad 0xaceb0f891e6551bb, 0x003a52a7cfcee3c6, // 123 + .quad 0xac7691840ac76918, 0x003a043a5ee0fa15, // 124 + .quad 0xac02b00ac02b00ac, 0x0039b66ab56e7112, // 125 + .quad 0xab8f69e28359cd11, 0x003969372d5921bb, // 126 + .quad 0xab1cbdd3e2970f60, 0x00391c9e2602ddfa, // 127 + .quad 0xaaaaaaaaaaaaaaab, 0x0038d09e04377bbb, // 128 + .quad 0xaa392f35dc17f00b, 0x003885353217460a, // 129 + .quad 0xa9c84a47a07f5638, 0x00383a621f01d214, // 130 + .quad 0xa957fab5402a55ff, 0x0037f0233f8135f4, // 131 + .quad 0xa8e83f5717c0a8e8, 0x0037a6770d359f5a, // 132 + .quad 0xa87917088e262b6f, 0x00375d5c06c14806, // 133 + .quad 0xa80a80a80a80a80b, 0x003714d0afb4c633, // 134 + .quad 0xa79c7b16ea64d422, 0x0036ccd3907bb709, // 135 + .quad 0xa72f05397829cbc1, 0x003685633649c151, // 136 + .quad 0xa6c21df6e1625c80, 0x00363e7e3307ee8e, // 137 + .quad 0xa655c4392d7b73a8, 0x0035f8231d4258ba, // 138 + .quad 0xa5e9f6ed347f0721, 0x0035b25090162b0e, // 139 + .quad 0xa57eb50295fad40a, 0x00356d052b1ff400, // 140 + .quad 0xa513fd6bb00a5140, 0x0035283f926a46f2, // 141 + .quad 0xa4a9cf1d96833751, 0x0034e3fe6e5cabea, // 142 + .quad 0xa44029100a440291, 0x0034a0406baadbcc, // 143 + .quad 0xa3d70a3d70a3d70a, 0x00345d043b44478a, // 144 + .quad 0xa36e71a2cb033128, 0x00341a489243e8ca, // 145 + .quad 0xa3065e3fae7cd0e0, 0x0033d80c29e05a93, // 146 + .quad 0xa29ecf163bb6500a, 0x0033964dbf5c3891, // 147 + .quad 0xa237c32b16cfd772, 0x0033550c13f6c382, // 148 + .quad 0xa1d139855f7268ee, 0x00331445ecdcc986, // 149 + .quad 0xa16b312ea8fc377d, 0x0032d3fa1319d0d6, // 150 + .quad 0xa105a932f2ca891f, 0x00329427538983c8, // 151 + .quad 0xa0a0a0a0a0a0a0a1, 0x003254cc7ec95ca2, // 152 + .quad 0xa03c1688732b3032, 0x003215e8692a9028, // 153 + .quad 0x9fd809fd809fd80a, 0x0031d779eaa43595, // 154 + .quad 0x9f747a152d7836d0, 0x0031997fdec5aad6, // 155 + .quad 0x9f1165e7254813e2, 0x00315bf924a933d8, // 156 + .quad 0x9eaecc8d53ae2ddf, 0x00311ee49ee6d3cb, // 157 + .quad 0x9e4cad23dd5f3a20, 0x0030e24133875f2f, // 158 + .quad 0x9deb06c9194aa416, 0x0030a60dcbf7c5aa, // 159 + .quad 0x9d89d89d89d89d8a, 0x00306a4954fc927a, // 160 + .quad 0x9d2921c3d6411308, 0x00302ef2bea5a284, // 161 + .quad 0x9cc8e160c3fb19b9, 0x002ff408fc420f05, // 162 + .quad 0x9c69169b30446dfa, 0x002fb98b04544bcd, // 163 + .quad 0x9c09c09c09c09c0a, 0x002f7f77d086781f, // 164 + .quad 0x9baade8e4a2f6e10, 0x002f45ce5d9ee128, // 165 + .quad 0x9b4c6f9ef03a3caa, 0x002f0c8dab74b53e, // 166 + .quad 0x9aee72fcf957c10f, 0x002ed3b4bce4e6d7, // 167 + .quad 0x9a90e7d95bc609a9, 0x002e9b4297c73e6e, // 168 + .quad 0x9a33cd67009a33cd, 0x002e633644e39a62, // 169 + .quad 0x99d722dabde58f06, 0x002e2b8ecfe75c01, // 170 + .quad 0x997ae76b50efd00a, 0x002df44b475b00d8, // 171 + .quad 0x991f1a515885fb37, 0x002dbd6abc97e780, // 172 + .quad 0x98c3bac74f5db00a, 0x002d86ec43be3f17, // 173 + .quad 0x9868c809868c8098, 0x002d50cef3ab208e, // 174 + .quad 0x980e4156201301c8, 0x002d1b11e5eed122, // 175 + .quad 0x97b425ed097b425f, 0x002ce5b436c32d10, // 176 + .quad 0x975a750ff68a58af, 0x002cb0b5050239fa, // 177 + .quad 0x97012e025c04b809, 0x002c7c13721ce019, // 178 + .quad 0x96a850096a850097, 0x002c47cea211c9a1, // 179 + .quad 0x964fda6c0964fda7, 0x002c13e5bb646783, // 180 + .quad 0x95f7cc72d1b887e9, 0x002be057e7141b13, // 181 + .quad 0x95a02568095a0257, 0x002bad24509383a7, // 182 + .quad 0x9548e4979e0829fd, 0x002b7a4a25bfefbe, // 183 + .quad 0x94f2094f2094f209, 0x002b47c896d8f0df, // 184 + .quad 0x949b92ddc02526e5, 0x002b159ed67811bb, // 185 + .quad 0x9445809445809446, 0x002ae3cc1988adbb, // 186 + .quad 0x93efd1c50e726b7c, 0x002ab24f973fe99c, // 187 + .quad 0x939a85c40939a85c, 0x002a81288914cc5b, // 188 + .quad 0x93459be6b009345a, 0x002a50562ab877df, // 189 + .quad 0x92f113840497889c, 0x002a1fd7ba0e80df, // 190 + .quad 0x929cebf48bbd90e5, 0x0029efac7725656b, // 191 + .quad 0x9249249249249249, 0x0029bfd3a42f218e, // 192 + .quad 0x91f5bcb8bb02d9cd, 0x0029904c8579e17d, // 193 + .quad 0x91a2b3c4d5e6f809, 0x002961166168d0d3, // 194 + .quad 0x9150091500915009, 0x00293230806d0653, // 195 + .quad 0x90fdbc090fdbc091, 0x0029039a2cfe8bab, // 196 + .quad 0x90abcc0242af3009, 0x0028d552b39580c2, // 197 + .quad 0x905a38633e06c43b, 0x0028a75962a35a0f, // 198 + .quad 0x9009009009009009, 0x002879ad8a8c397c, // 199 + .quad 0x8fb823ee08fb823f, 0x00284c4e7da06171, // 200 + .quad 0x8f67a1e3fdc26178, 0x00281f3b9015c16f, // 201 + .quad 0x8f1779d9fdc3a219, 0x0027f27418019bf5, // 202 + .quad 0x8ec7ab397255e41d, 0x0027c5f76d52450e, // 203 + .quad 0x8e78356d1408e783, 0x002799c4e9c8f94d, // 204 + .quad 0x8e2917e0e702c6cd, 0x00276ddbe8f3cca0, // 205 + .quad 0x8dda520237694809, 0x0027423bc827b0a6, // 206 + .quad 0x8d8be33f95d71590, 0x002716e3e67a921c, // 207 + .quad 0x8d3dcb08d3dcb08d, 0x0026ebd3a4bd8d01, // 208 + .quad 0x8cf008cf008cf009, 0x0026c10a657736fa, // 209 + .quad 0x8ca29c046514e023, 0x002696878cddffb1, // 210 + .quad 0x8c55841c815ed5ca, 0x00266c4a80d2a6b2, // 211 + .quad 0x8c08c08c08c08c09, 0x00264252a8dac681, // 212 + .quad 0x8bbc50c8deb420c0, 0x0026189f6e1b7473, // 213 + .quad 0x8b70344a139bc75a, 0x0025ef303b53f50e, // 214 + .quad 0x8b246a87e19008b2, 0x0025c6047cd8847d, // 215 + .quad 0x8ad8f2fba9386823, 0x00259d1ba08d32c5, // 216 + .quad 0x8a8dcd1feeae465c, 0x0025747515e0d378, // 217 + .quad 0x8a42f8705669db46, 0x00254c104dc80080, // 218 + .quad 0x89f87469a23920e0, 0x002523ecbab82fae, // 219 + .quad 0x89ae4089ae4089ae, 0x0024fc09d0a2dace, // 220 + .quad 0x89645c4f6e055dec, 0x0024d46704f0b9de, // 221 + .quad 0x891ac73ae9819b50, 0x0024ad03ce7d0f24, // 222 + .quad 0x88d180cd3a4133d7, 0x002485dfa59104dc, // 223 + .quad 0x8888888888888889, 0x00245efa03df1c1d, // 224 + .quad 0x883fddf00883fddf, 0x00243852647eaccb, // 225 + .quad 0x87f78087f78087f8, 0x002411e843e77632, // 226 + .quad 0x87af6fd5992d0d40, 0x0023ebbb1fed4014, // 227 + .quad 0x8767ab5f34e47ef1, 0x0023c5ca77bb8be3, // 228 + .quad 0x872032ac13008720, 0x0023a015cbd155d3, // 229 + .quad 0x86d905447a34acc6, 0x00237a9c9dfce59b, // 230 + .quad 0x869222b1acf1ce96, 0x0023555e7157ae8e, // 231 + .quad 0x864b8a7de6d1d608, 0x0023305aca423ed8, // 232 + .quad 0x86053c345a0b8473, 0x00230b912e603d96, // 233 + .quad 0x85bf37612cee3c9b, 0x0022e70124947795, // 234 + .quad 0x85797b917765ab89, 0x0022c2aa34fcfa72, // 235 + .quad 0x8534085340853408, 0x00229e8be8ef3de8, // 236 + .quad 0x84eedd357c1b0085, 0x00227aa5caf45b0a, // 237 + .quad 0x84a9f9c8084a9f9d, 0x002256f766c5512f, // 238 + .quad 0x84655d9bab2f1008, 0x002233804947585d, // 239 + .quad 0x8421084210842108, 0x0022104000884100, // 240 + .quad 0x83dcf94dc7570ce1, 0x0021ed361bbae0a0, // 241 + .quad 0x839930523fbe3368, 0x0021ca622b338b7a, // 242 + .quad 0x8355ace3c897db10, 0x0021a7c3c0649abe, // 243 + .quad 0x83126e978d4fdf3b, 0x0021855a6ddaff33, // 244 + .quad 0x82cf750393ac3319, 0x00216325c73ae026, // 245 + .quad 0x828cbfbeb9a020a3, 0x00214125613c4656, // 246 + .quad 0x824a4e60b3262bc5, 0x00211f58d1a7d2cb, // 247 + .quad 0x8208208208208208, 0x0020fdbfaf538145, // 248 + .quad 0x81c635bc123fdf8e, 0x0020dc59921f7638, // 249 + .quad 0x81848da8faf0d277, 0x0020bb2612f2d806, // 250 + .quad 0x814327e3b94f462f, 0x00209a24cbb8b365, // 251 + .quad 0x8102040810204081, 0x00207955575ceaab, // 252 + .quad 0x80c121b28bd1ba98, 0x002058b751c92feb, // 253 + .quad 0x8080808080808081, 0x0020384a57e209a8, // 254 + .quad 0x8040201008040201, 0x0020180e0783e1f9, // 255 + +#endif // FASTDIV_TABLES diff --git a/private/crt32/misc/alpha/ghandler.c b/private/crt32/misc/alpha/ghandler.c new file mode 100644 index 000000000..712d15fe4 --- /dev/null +++ b/private/crt32/misc/alpha/ghandler.c @@ -0,0 +1,435 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ghandler.c + +Abstract: + + This module implements the C specific exception handler that provides + structured exception handling for code generated by the GEM compiler. + +Author: + + John Parks (parks) 12-Jan-1993 + Thomas Van Baak (tvb) 28-Jan-1993 + +Environment: + + Any mode. + +Revision History: + +--*/ + +#include "nt.h" + +// +// Define procedure prototypes for exception filter and termination handler +// execution routines defined in jmpunwnd.s. +// + +LONG +__C_ExecuteExceptionFilter ( + PEXCEPTION_POINTERS ExceptionPointers, + EXCEPTION_FILTER ExceptionFilter, + ULONG EstablisherFrame + ); + +ULONG +__C_ExecuteTerminationHandler ( + BOOLEAN AbnormalTermination, + TERMINATION_HANDLER TerminationHandler, + ULONG EstablisherFrame + ); + +// +// Define local procedure prototypes. +// + +EXCEPTION_DISPOSITION +_OtsCSpecificHandler ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PDISPATCHER_CONTEXT DispatcherContext + ); + +ULONG +_OtsLocalFinallyUnwind ( + IN PSEH_CONTEXT SehContext, + IN PSEH_BLOCK TargetSeb, + IN PVOID RealFramePointer + ); + +// +// Define local macros. +// + +#define IS_EXCEPT(Seb) ((Seb)->JumpTarget != 0) +#define IS_FINALLY(Seb) ((Seb)->JumpTarget == 0) + +// +// Initialize an exception record for the unwind with the SEB of the target +// included as one information parameter. This is done so that the target +// frame of the unwind may execute all the finally handlers necessary given +// the SEB pointer at the unwind target. +// + +#define MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, Seb) { \ + ExceptionRecord->ExceptionCode = STATUS_UNWIND; \ + ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING; \ + ExceptionRecord->ExceptionRecord = NULL; \ + ExceptionRecord->ExceptionAddress = 0; \ + ExceptionRecord->NumberParameters = 1; \ + ExceptionRecord->ExceptionInformation[0] = (ULONG)(Seb); \ + } + +EXCEPTION_DISPOSITION +_OtsCSpecificHandler ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PDISPATCHER_CONTEXT DispatcherContext + ) + +/*++ + +Routine Description: + + This function walks up the list of SEB's associated with the specified + procedure and calls except filters and finally handlers as necessary. + + It is called in two different contexts: + (i) by the exception dispatcher after an exception is raised + (ii) by the unwinder during an unwind operation + + In the first case, is searches the SEB list for except filters to evaluate. + In the second case, it searches for finally handlers to execute. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + EstablisherFrame - Supplies a (virtual frame) pointer to the frame of the + establisher function. + + ContextRecord - Supplies a pointer to a context record. + + DispatcherContext - Supplies a pointer to the exception dispatcher or + unwind dispatcher context. + +Return Value: + + If the exception is handled by one of the exception filter routines, then + there is no return from this routine and RtlUnwind is called. Otherwise, + an exception disposition value of continue execution or continue search is + returned. + +Notes: + In context (i) there are 3 possibilities: + + (a) If an exception filter returns a value greater that 0 (meaning + that the associated handler should be invoked) there is no + return from this function. RtlUnwind is called to unwind the + stack to the exception handler corresponding to that filter. + + (b) If an exception filter returns a value less than 0 (meaning + that the exception should be dismissed), this routine returns + value ExceptionContinueExecution. + + (c) If every filter returns value 0 (meaning that the search for a + handler should continue elsewhere), this function returns + ExceptionContinueSearch. + + In context (ii) there are 2 possibilities: + + (d) If no branches are detected out of finally handlers, this + function returns ExceptionContinueSearch. + + (e) If a branch is detected out of a finally handler, there is no + return from this routine. RtlUnwind is called to unwind to the + branch target (and cancel the current unwind). + + There may be long jumps out of both except filters and finally handlers + in which case this routine will be peeled off the stack without returning. + +--*/ + +{ + + ULONG ContinuationAddress; + EXCEPTION_FILTER ExceptionFilter; + PVOID ExceptionHandler; + EXCEPTION_POINTERS ExceptionPointers; + LONG FilterValue; + ULONG RealFramePointer; + PSEH_BLOCK Seb; + PSEH_CONTEXT SehContext; + PSEH_BLOCK TargetSeb; + TERMINATION_HANDLER TerminationHandler; + + // + // Get the address of the SEH context which is at some negative offset + // from the virtual frame pointer. For GEM, the handler data field of + // the function entry contains that offset. The current SEB pointer and + // the RFP (static link) are obtained from the SEH context. + // + + SehContext = (PSEH_CONTEXT)((ULONG)EstablisherFrame + + (LONG)DispatcherContext->FunctionEntry->HandlerData); + RealFramePointer = SehContext->RealFramePointer; + + // + // If this is a dispatching context, walk up the list of SEBs evaluating + // except filters. + // + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { + + // + // Set up the ExceptionPointers structure that is used by except + // filters to obtain data for the GetExceptionInformation intrinsic + // function. Copy the current SEB pointer into a local variable + // because the real SEB pointer is only modified in unwind contexts. + // + + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + + for (Seb = SehContext->CurrentSeb; Seb != NULL; Seb = Seb->ParentSeb) { + if (IS_EXCEPT(Seb)) { + + // + // This is an except filter. Get the addresses of the filter + // and exception handler from the SEB, then call the except + // filter. + // + + ExceptionFilter = (EXCEPTION_FILTER)Seb->HandlerAddress; + ExceptionHandler = (PVOID)Seb->JumpTarget; + + FilterValue = __C_ExecuteExceptionFilter(&ExceptionPointers, + ExceptionFilter, + RealFramePointer); + + // + // If the except filter < 0, dismiss the exception. If > 0, + // store the exception code on the stack for the except + // handler, modify the given ExceptionRecord so that finally + // handlers will be called properly during the unwind, then + // unwind down to the except handler. If = 0, resume the + // search for except filters. + // + + if (FilterValue < 0) { + return ExceptionContinueExecution; + + } else if (FilterValue > 0) { + SehContext->ExceptionCode = ExceptionRecord->ExceptionCode; + MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, + Seb->ParentSeb); + RtlUnwind(EstablisherFrame, + ExceptionHandler, + ExceptionRecord, + 0); + } + } + } + + } else if (!IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)) { + + // + // This is an unwind but is not the target frame. Since the function + // is being terminated, finally handlers for all try bodies that are + // presently in scope must be executed. Walk up the SEB list all the + // way to the top executing finally handlers. This corresponds to + // exiting all try bodies that are presently in scope. + // + + while (SehContext->CurrentSeb != NULL) { + + // + // Get the address of the SEB and then update the SEH context. + // + + Seb = SehContext->CurrentSeb; + SehContext->CurrentSeb = Seb->ParentSeb; + + if (IS_FINALLY(Seb)) { + + // + // This is a finally handler. Get the address of the handler + // from the SEB and call the finally handler. + // + + TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress; + ContinuationAddress = + __C_ExecuteTerminationHandler(TRUE, + TerminationHandler, + RealFramePointer); + + // + // If the finally handler returns a non-zero result, there + // was a branch out of the handler (to that address) and this + // routine should unwind to that target. + // + + if (ContinuationAddress != 0) { + MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, + SehContext->CurrentSeb); + RtlUnwind(EstablisherFrame, + (PVOID)ContinuationAddress, + ExceptionRecord, + 0); + } + } + } + + } else { + + // + // This is the target frame of an unwind. Since the target may be + // in a different try scope than the one defined by the current SEB + // pointer, finally handlers between the two scopes must execute. + // Walk up the SEB list from the current SEB to the target SEB and + // execute all finally handlers encountered. + // + + TargetSeb = (PSEH_BLOCK)ExceptionRecord->ExceptionInformation[0]; + ContinuationAddress = _OtsLocalFinallyUnwind(SehContext, + TargetSeb, + (PVOID)RealFramePointer); + if (ContinuationAddress != 0) { + + // + // A non-zero result indicates there was a branch out of a + // finally handler that was being executed during the unwind. + // This routine should unwind to that address. + // + + MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, + SehContext->CurrentSeb); + RtlUnwind(EstablisherFrame, + (PVOID)ContinuationAddress, + ExceptionRecord, + 0); + } + } + + // + // Continue search for exception or termination handlers. + // + + return ExceptionContinueSearch; +} + +ULONG +_OtsLocalFinallyUnwind ( + IN PSEH_CONTEXT SehContext, + IN PSEH_BLOCK TargetSeb, + IN PVOID RealFramePointer + ) + +/*++ + +Routine Description: + + This function walks up the SEB tree of the current procedure from the + current SEB to the target SEB and executes all the finally handlers it + encounters. + + Calls to this function are inserted into user code by the compiler when + there are branches out of guarded regions that may require finally + handlers to execute. + + This function is also called from _OtsCSpecificHandler when the target + frame is reached during an unwind operation. There may be finally handlers + that should execute before resuming execution at the unwind target. + +Arguments: + + SehContext - Supplies the address of the SEH context structure which is + located in the stack frame. + + TargetSeb - Supplies the address of the SEB corresponding to the branch + target address. + + RealFramePointer - Supplies the (real frame) pointer of the establisher + frame, which is the current stack frame. This is used to set up the + static link if a finally handler is invoked. + +Return Value: + + If a branch out of a finally handler is detected, the function value is + the address of the branch target. Otherwise, the function value is zero. + +--*/ + +{ + + ULONG ContinuationAddress; + BOOLEAN Nested; + PSEH_BLOCK Seb; + TERMINATION_HANDLER TerminationHandler; + + // + // If the SEB pointers are the same, no finally handlers need to execute. + // The branch is to a target location in the same guarded scope. + // + + if (SehContext->CurrentSeb == TargetSeb) { + return 0; + } + + // + // If the current SEB scope is not nested within the target SEB scope, no + // finally handlers need to execute. Reset the current SEB pointer to the + // target SEB pointer and return. + // + + Nested = FALSE; + Seb = SehContext->CurrentSeb; + + while (Seb != NULL) { + Seb = Seb->ParentSeb; + if (Seb == TargetSeb) { + Nested = TRUE; + break; + } + } + if (Nested == FALSE) { + SehContext->CurrentSeb = TargetSeb; + return 0; + } + + // + // Walk up the list of SEB blocks executing finally handlers. If a branch + // out of a finally is encountered along the way, return the target + // address, otherwise return 0. + // + + while (SehContext->CurrentSeb != TargetSeb) { + + // + // Get the address of the SEB and then update the SEH context. + // + + Seb = SehContext->CurrentSeb; + SehContext->CurrentSeb = Seb->ParentSeb; + + if (IS_FINALLY(Seb)) { + TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress; + ContinuationAddress = + __C_ExecuteTerminationHandler(TRUE, + TerminationHandler, + (ULONG)RealFramePointer); + if (ContinuationAddress != 0) { + return ContinuationAddress; + } + } + } + return 0; +} diff --git a/private/crt32/misc/alpha/insv.s b/private/crt32/misc/alpha/insv.s new file mode 100644 index 000000000..7d0956103 --- /dev/null +++ b/private/crt32/misc/alpha/insv.s @@ -0,0 +1,158 @@ + #+ + # Copyright 1991, 1994 Digital Equipment Corporation + # + # int ots_insv(char *addr, int position, unsigned size, int value) + # + # Arbitrary bitfield insertion, longword granularity + # + # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_ext[z]v + # + # 001 5 Sep 1991 KDG Initial version + # + # 002 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 003 22 Sep 1992 KDG Add case-sensitive name + # + # 004 26 Jan 1993 KDG Add underscore + # + # 005 19 Apr 1994 kdg Longword granularity version based on quadword + # granularity version 004 + +#include "ots_defs.hs" + + # Totally general field insertion - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. Longword granularity. + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # r19 - input value + # + # This is based on the original insert routine modified for longword + # granularity. This routine could probably be improved. (It does + # a "reasonable" job, but hasn't had as much attention as the quadword + # granularity version. Fields contained in a single longword are + # roughly the same cost as the quadword granularity version. Fields + # contained in two longwords in the same quadword are somewhat slower, + # while the two longword spanning a quadword case is roughly comparable. + # The 3 longword case is relatively slow [2 mispredicted branches, + # on unnecessary safe speculative load, could potentially use better + # scheduling too.]) + # + .globl _OtsFieldInsert + .ent _OtsFieldInsert +_OtsFieldInsert: + .set noat + .set noreorder + ble r18, noacc # check for zero size - no memory access + sra r17, 3, r27 # get byte part of bit offset (signed!) + addq r16, r27, r16 # add to initial base addr. + and r17, 7, r17 # get bit-in-byte from bit offset + and r16, 3, r27 # get byte-in-longword (must be clean for compares) + bic r16, 3, r16 # get a longword aligned address + s8addq r27, r17, r17 # form the true bit offset in the longword + ldl r28, (r16) # load first or only longword + addq r17, r18, r27 # get bit offset of bit following field + subq r27, 32, r0 # if <=32, field is contained in 1 longword + bgt r0, multiple # handle multi-longword case if not + # Common case of field in single LW - fall through + negq r27, r27 # <5:0> = bits for right shift + negq r18, r0 # bits for left shift (wordlength-is) + not r31, r1 # all ones + sll r1, r0, r1 # shift mask to high bits + sll r19, r0, r19 # shift source to high bits (hand interleaving for better sched) + srl r1, r27, r1 # and into position + srl r19, r27, r19 # and into position + bic r28, r1, r28 # clear the bits... + bis r28, r19, r28 # insert them + stl r28, (r16) # put the value back... +noacc: ret r31, (r26) + + # At this point: + # Field is known to be contained in at least 2 longwords + # r0 is bit position past end of field, -32 + # r1 junk + # r16 is longword aligned + # r17 is bit offset in longword + # r18 is field size + # r19 is value to store + # r27 is bit position past end of field + # r28 first lw from memory + # +multiple: + subq r0, 32, r27 # if <=64, the field is contained in 2 longwords + ldl r1, 4(r16) # load the 2nd longword (safe) + bgt r27, three # handle 3 longword case (rare...) + not r31, r27 # all ones + sll r27, r17, r27 # get mask in correct place + sll r19, r17, r17 # get insert value to top of register + bic r28, r27, r28 # clear bits in target + bis r28, r17, r28 # merge the field in + srl r1, r0, r1 # clear bits in target + negq r18, r27 # + sll r19, r27, r19 # shift to high bits + negq r0, r27 # + srl r19, r27, r19 # and into position + sll r1, r0, r1 # + stl r28, (r16) # store the first longword + bis r1, r19, r1 # merge + stl r1, 4(r16) # store back the second longword + ret r31, (r26) + + # At this point: + # Field is known to be contained in exactly 3 longwords + # r0 is bit position past end of field, -32 + # r1 value loaded for 2nd longword (which will be totally overwritten - i.e. junk) + # r16 is longword aligned + # r17 is bit offset in longword + # r18 is field size + # r19 is value to store + # r27 is bit position past end of field -64 + # r28 first lw from memory + # + # Three word case is roughly similar to two word case, except + # the middle store isn't a merge, just a real store, and the offsets + # for the 3rd word need to be adjusted. (This case hasn't + # received much attention and could probably be improved by + # at least a few instructions...) + # +three: + not r31, r0 # all ones + sll r0, r17, r0 # get mask in correct place + sll r19, r17, r1 # get insert value to top of register + bic r28, r0, r28 # clear bits in target + bis r28, r1, r28 # merge the field in + ldl r1, 8(r16) # load the 3rd longword + lda r0, 32(r31) # load 32 + stl r28, (r16) # store the first longword + subq r0, r17, r0 # shift amount + srl r19, r0, r28 # discard bits already stored + negq r18, r0 # + srl r1, r27, r1 # clear bits in target + sll r19, r0, r19 # shift to high bits + negq r27, r0 # + srl r19, r0, r19 # and into position + sll r1, r27, r1 # + stl r28, 4(r16) # store second complete longword + bis r1, r19, r1 # merge + stl r1, 8(r16) # store back the third longword + ret r31, (r26) + + .set at + .set reorder + .end _OtsFieldInsert diff --git a/private/crt32/misc/alpha/insvvol.s b/private/crt32/misc/alpha/insvvol.s new file mode 100644 index 000000000..11c0c3eed --- /dev/null +++ b/private/crt32/misc/alpha/insvvol.s @@ -0,0 +1,137 @@ + #+ + # Copyright 1991, Digital Equipment Corporation + # + # int ots_insv_vol(char *addr, int position, unsigned size, int value) + # + # Arbitrary signed bitfield extraction for volatile cases + # + # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # See also: ots_ext[z]v + # + # 001 5 Sep 1991 KDG Initial version + # + # 002 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 003 5 Oct 1992 KDG Initial volatile version based on non-volatile + # version + # + # 004 10 Nov 1992 KDG Case-sensitive name + # + # 005 26 Jan 1993 KDG Add underscore + # + # 006 1 Sep 1994 RBG Fix aligned longword and quadword cases, + # check for bit 0 within byte GEM_BUGS #3545 + +#include "ots_defs.hs" + + # Totally general field insertion - arbitrary run-time field of 0-64 bits + # at an unknown alignment target. + # + # Volatile/byte granularity version notes: + # + # - Aligned quadword stores must be done using exactly STQ + # + # - Aligned longword stores must be done using exactly STL + # + # - All other stores must be done using LDx_L/STx_C to avoid + # corrupting any adjacent data and provide atomic updates + # for aligned data + # + # The first two items are required in case this routine is called for + # volatile references so that I/O space accesses are handled correctly. + # (Normally, those references are handled in-line, but if for some + # reason they wind up coming through here, they must still be correct.) + # + # Conceptually, this operation takes a 67 bit bit-address, which is the sum + # of a byte-aligned memory address and the bit offset (which is signed). + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|Q|L|W|B| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | | | | | | | | | | | | | | | | | | | | | | | | | |.|.|.|b|b|b| + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # Inputs: + # r16 - input address + # r17 - input bit offset + # r18 - input size + # r19 - input value + # + # This is based on the code GEM generates when not using an out-of-line + # routine, though it has better by-hand register packing to allow + # multiple issue. + # + .globl _OtsFieldInsertVolatile + .ent _OtsFieldInsertVolatile +_OtsFieldInsertVolatile: + .set noat + .set noreorder + sra r17, 3, r27 # get byte part of bit offset (signed!) + ble r18, noacc # check for zero size - no memory access + cmpeq r18, 32, r28 # Aligned longword(1) - is the size exactly 32b? + addq r16, r27, r16 # add to initial base addr. + and r16, 3, r27 # check for special case of an aligned longword + cmpult r27, r28, r28 # Aligned longword(2) - byte 0 within longword + and r17, 7, r17 # get bit-in-byte from bit offset + cmpult r17, r28, r28 # Aligned longword(3) - bit 0 within byte + cmpeq r18, 64, r0 # Aligned quadword(1) - is the size exactly 64b? + and r16, 7, r27 # get byte-in-quadword (must be clean for cmpule) + bne r28, longwd # if aligned longword, store exactly a longword using stl + cmpult r27, r0, r0 # Aligned quadword(2) - byte 0 within quadword + cmpult r17, r0, r0 # Aligned quadword(3) - bit 0 within byte + s8addq r27, r17, r17 # form the true bit offset in the quadword + bne r0, quadwd # if aligned quadword, store exactly a quadword using stq + addq r17, r18, r27 # get bit offset of bit following field + cmpule r27, 64, r0 # if <=64, field is contained in 1 quadword + bic r16, 7, r16 # clear unaligned bits in address for locked operations + not r31, r1 # all ones + beq r0, double # handle double case if not + # Common case of field in single QW - fall through + negq r27, r27 # <5:0> = bits for right shift + addq r27, r17, r0 # bits for left shift (wordlength-is) + sll r1, r0, r1 # shift mask to high bits + sll r19, r0, r19 # shift source to high bits (hand interleaving for better sched) + srl r1, r27, r1 # and into position + srl r19, r27, r19 # and into position +sinrty: ldq_l r28, (r16) # load first or only quadword + bic r28, r1, r28 # clear the bits... + bis r28, r19, r28 # insert them + stq_c r28, (r16) # put the value back... + blbc r28, sinfl # check for failing interlock/retry +noacc: ret r31, (r26) + +double: + sll r1, r17, r0 # get mask in correct place + sll r19, r17, r17 # get insert value to top of register + negq r18, r1 # + sll r19, r1, r19 # shift to high bits + negq r27, r1 # + srl r19, r1, r19 # and into position +firrty: ldq_l r28, (r16) # load first or only quadword + bic r28, r0, r28 # clear bits in target + bis r28, r17, r28 # merge the field in + stq_c r28, (r16) # store the first word + blbc r28, firfl # check for failing interlock/retry +secrty: ldq_l r28, 8(r16) # load the 2nd quadword + srl r28, r27, r28 # clear bits in target + sll r28, r27, r28 # + bis r28, r19, r28 # merge + stq_c r28, 8(r16) # store back + blbc r28, secfl # check for failing interlock/retry + ret r31, (r26) +longwd: stl r19, (r16) # store aligned longword + ret r31, (r26) +quadwd: stq r19, (r16) # store aligned quadword + ret r31, (r26) + # out-of-line retry cases +sinfl: br r31, sinrty # re-try the locked operation for the single case +firfl: br r31, firrty # re-try the locked operation for the 1st part of the two-part case +secfl: br r31, secrty # re-try the locked operation for the 2nd part of the two-part case + + .set at + .set reorder + .end _OtsFieldInsertVolatile diff --git a/private/crt32/misc/alpha/jmpuwind.s b/private/crt32/misc/alpha/jmpuwind.s new file mode 100644 index 000000000..934b9d549 --- /dev/null +++ b/private/crt32/misc/alpha/jmpuwind.s @@ -0,0 +1,167 @@ +// TITLE("Handler Stubs and Jump to Unwind") +//++ +// +// Copyright (c) 1992 Microsoft Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// jmpuwind.s +// +// Abstract: +// +// This module implements the Alpha acc compiler specific routines to call +// exception handlers and to jump to the runtime library unwind routines. +// +// Author: +// +// David N. Cutler (davec) 12-Sep-1990 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Thomas Van Baak (tvb) 30-Apr-1992 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + + SBTTL("Execute Exception Filter") +//++ +// +// ULONG +// __C_ExecuteExceptionFilter ( +// PEXCEPTION_POINTERS ExceptionPointers, +// EXCEPTION_FILTER ExceptionFilter, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function sets the static link and transfers control to the specified +// exception filter routine. +// +// Arguments: +// +// ExceptionPointers (a0) - Supplies a pointer to the exception pointers +// structure. +// +// ExceptionFilter (a1) - Supplies the address of the exception filter +// routine. +// +// EstablisherFrame (a2) - Supplies the establisher frame pointer. +// +// Return Value: +// +// The value returned by the exception filter routine. +// +//-- + + LEAF_ENTRY(__C_ExecuteExceptionFilter) + +// +// The protocol for calling exception filters used by the acc compiler is +// that the uplevel frame pointer is passed in register v0 and the pointer +// to the exception pointers structure is passed in register a0. The GEM +// C compiler expects the static link in t0. Here both registers are set. +// + + mov a2, v0 // set static link + mov a2, t0 // set alternate static link + jmp zero, (a1) // transfer control to exception filter + + .end __C_ExecuteExceptionFilter + + SBTTL("Execute Termination Handler") +//++ +// +// ULONG +// __C_ExecuteTerminationHandler ( +// BOOLEAN AbnormalTermination, +// TERMINATION_HANDLER TerminationHandler, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function sets the static link and transfers control to the specified +// termination handler routine. +// +// Arguments: +// +// AbnormalTermination (a0) - Supplies a boolean value that determines +// whether the termination is abnormal. +// +// TerminationHandler (a1) - Supplies the address of the termination handler +// routine. +// +// EstablisherFrame (a2) - Supplies the establisher frame pointer. +// +// Return Value: +// +// The value returned by the termination handler routine, if any. +// +//-- + + LEAF_ENTRY(__C_ExecuteTerminationHandler) + +// +// The protocol for calling termination handlers used by the acc compiler +// is that the uplevel frame pointer is passed in register v0 and the boolean +// abnormal termination value is passed in register a0. The GEM C compiler +// expects the static link in t0. Here both registers are set. +// + + mov a2, v0 // set static link + mov a2, t0 // set alternate static link + jmp zero, (a1) // transfer control to termination handler + + .end __C_ExecuteTerminationHandler + + SBTTL("Jump to Unwind") +//++ +// +// VOID +// __jump_unwind ( +// IN PVOID EstablishFrame, +// IN PVOID TargetPc +// ) +// +// Routine Description: +// +// This function transfers control to unwind. It is used by the acc +// compiler when a goto out of the body of a try statement occurs. +// +// Arguments: +// +// EstablishFrame (a0) - Supplies the establisher frame pointer of the +// target of the unwind. +// +// TargetPc (a1) - Supplies the target instruction address where control +// is to be transferred to after the unwind operation is complete. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(__jump_unwind) + +// +// The first two arguments are the same as those required by unwind. Set the +// second two arguments and jump to unwind. This thunk is necessary to avoid +// name space pollution. The compiler should not generate a call directly to +// RtlUnwind. +// + + mov zero, a2 // set NULL exception record address + mov zero, a3 // set target return value of 0 + br zero, RtlUnwind // unwind to specified target + + .end __jump_unwind diff --git a/private/crt32/misc/alpha/longjmp.s b/private/crt32/misc/alpha/longjmp.s new file mode 100644 index 000000000..412e3e655 --- /dev/null +++ b/private/crt32/misc/alpha/longjmp.s @@ -0,0 +1,192 @@ +// TITLE("Long Jump") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// longjmp.s +// +// Abstract: +// +// This module implements the Alpha specific routine to perform a long +// jump operation. Three jump buffer types are supported: unsafe, safe +// acc-style (virtual frame pointer, PC mapped SEH scope), and safe +// GEM-style (real frame pointer, SEB-based SEH context). +// +// N.B. This routine conditionally provides UNSAFE handling of longjmp +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an unitialized variable +// has been set to a nonzero value. +// +// Author: +// +// David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Thomas Van Baak (tvb) 22-Apr-1993 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + +// +// Define jump buffer types. +// +// _JMPBUF_TYPE_ZERO was used for Beta2 which functions the same as +// _JMPBUF_TYPE_ACC. +// +// _JMPBUF_TYPE_FAST is for jump buffers containing the set of +// non-volatile integer and floating registers. This form +// of setjmp/longjmp is not compatible with SEH. +// +// _JMPBUF_TYPE_ACC is for setjmp/longjmp compatible with SEH. +// The Alpha acc compiler uses a virtual frame pointer. +// +// _JMPBUF_TYPE_GEM is for setjmp/longjmp compatible with SEH. +// The Alpha GEM C compiler uses a real frame pointer, and +// SEH scope is maintained with a SEB pointer. +// + +#define _JMPBUF_TYPE_ZERO 0 +#define _JMPBUF_TYPE_FAST 1 +#define _JMPBUF_TYPE_ACC 2 +#define _JMPBUF_TYPE_GEM 3 + + SBTTL("Long Jump") +//++ +// +// int +// longjmp ( +// IN jmp_buf JumpBuffer, +// IN int ReturnValue +// ) +// +// Routine Description: +// +// This function performs a long jump to the context specified by the +// jump buffer. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer that contains +// jump information. +// +// ReturnValue (a1) - Supplies the value that is to be returned to the +// caller of set jump. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(longjmp) + + ldil t0, 1 // force nonzero value, if + cmoveq a1, t0, a1 // given return value is zero + + ldl t1, JbType(a0) // get setjmp context type flag + subq t1, 1, t2 // if eq 1, fast, unsafe longjmp + bne t2, 10f // otherwise, provide safe longjmp + +// +// Type 0x1: Provide unsafe handling of longjmp. +// + + mov a1, v0 // set return value + + ldt f2, JbFltF2(a0) // restore floating registers f2 - f9 + ldt f3, JbFltF3(a0) // + ldt f4, JbFltF4(a0) // + ldt f5, JbFltF5(a0) // + ldt f6, JbFltF6(a0) // + ldt f7, JbFltF7(a0) // + ldt f8, JbFltF8(a0) // + ldt f9, JbFltF9(a0) // + + ldq s0, JbIntS0(a0) // restore integer registers s0 - s6/fp + ldq s1, JbIntS1(a0) // + ldq s2, JbIntS2(a0) // + ldq s3, JbIntS3(a0) // + ldq s4, JbIntS4(a0) // + ldq s5, JbIntS5(a0) // + ldq fp, JbIntS6(a0) // + + ldq a1, JbFir(a0) // get setjmp return address + ldq sp, JbIntSp(a0) // restore stack pointer + jmp zero, (a1) // jump back to setjmp site + +// +// Type 0x0: Provide safe handling of longjmp (idw 404 style). +// Type 0x2: Provide safe handling of longjmp (acc style). +// + +10: bic t1, 0x2, t2 // if 0 or 2, safe acc longjmp + bne t2, longjmpRfp // if not, safe GEM longjmp + + mov a1, a3 // set return value + mov zero, a2 // set exception record addres + ldl a1, JbPc(a0) // set target instruction address + ldl a0, JbFp(a0) // set target virtual frame pointer + br zero, RtlUnwind // finish in common code + + .end longjmp + + SBTTL("Long Jump - GEM") + + .struct 0 +LjRa: .space 8 // saved return address + .space 8 // padding for 16-byte stack alignment +LjEr: .space ExceptionRecordLength // local exception record +LongjmpFrameLength: + +// +// Type 0x3: Provide safe handling of longjmp (GEM style). +// + + NESTED_ENTRY(longjmpRfp, LongjmpFrameLength, ra) + + lda sp, -LongjmpFrameLength(sp) // allocate stack frame + stq ra, LjRa(sp) // save return address + + PROLOGUE_END + +// +// Set up the following local exception record: +// +// ExceptionRecord.ExceptionCode = STATUS_UNWIND; +// ExceptionRecord.ExceptionFlags = EXCEPTION_UNWINDING; +// ExceptionRecord.ExceptionRecord = NULL; +// ExceptionRecord.ExceptionAddress = 0; +// ExceptionRecord.NumberParameters = 1; +// ExceptionRecord.ExceptionInformation[0] = Seb; +// + +10: mov a1, a3 // set return value + lda a2, LjEr(sp) // set exception record address + + ldil t0, STATUS_UNWIND // get status code + stl t0, ErExceptionCode(a2) // store in exception record + ldil t1, EXCEPTION_UNWINDING // get exception flags + stl t1, ErExceptionFlags(a2) // store in exception record + stl zero, ErExceptionRecord(a2) // store in exception record + stl zero, ErExceptionAddress(a2) // store in exception record + ldil t2, 1 // get number of parameters + stl t2, ErNumberParameters(a2) // store in exception record + ldl t3, JbSeb(a0) // get SEB pointer + stl t3, ErExceptionInformation(a2) // store in exception record + ldl a1, JbPc(a0) // set target instruction address + ldl a0, JbFp(a0) // set target real frame pointer + + bsr ra, RtlUnwindRfp // finish in common code + + .end longjmpRfp diff --git a/private/crt32/misc/alpha/ots_as.hs b/private/crt32/misc/alpha/ots_as.hs new file mode 100644 index 000000000..127fe6382 --- /dev/null +++ b/private/crt32/misc/alpha/ots_as.hs @@ -0,0 +1,38 @@ +/* Definitions common to all systems using the "as" assembler (OSF,WNT) */ +/* Define mov to be bis from $31 so it can take a literal... */ +#define mov bis $31, +#define not ornot $31, +/* Define register aliases */ +#define r0 $0 +#define r1 $1 +#define r2 $2 +#define r3 $3 +#define r4 $4 +#define r5 $5 +#define r6 $6 +#define r7 $7 +#define r8 $8 +#define r9 $9 +#define r10 $10 +#define r11 $11 +#define r12 $12 +#define r13 $13 +#define r14 $14 +#define r15 $15 +#define r16 $16 +#define r17 $17 +#define r18 $18 +#define r19 $19 +#define r20 $20 +#define r21 $21 +#define r22 $22 +#define r23 $23 +#define r24 $24 +#define r25 $25 +#define r26 $26 +#define r27 $27 +#define r28 $28 +#define r29 $29 +#define sp $sp +#define gp $gp +#define r31 $31 diff --git a/private/crt32/misc/alpha/ots_defs.hs b/private/crt32/misc/alpha/ots_defs.hs new file mode 100644 index 000000000..d3a62a478 --- /dev/null +++ b/private/crt32/misc/alpha/ots_defs.hs @@ -0,0 +1,3 @@ +/* OSF-specific definitions */ +#define WNT 1 +#include "ots_as.hs" diff --git a/private/crt32/misc/alpha/otsdiv.s b/private/crt32/misc/alpha/otsdiv.s new file mode 100644 index 000000000..cafb9b87e --- /dev/null +++ b/private/crt32/misc/alpha/otsdiv.s @@ -0,0 +1,1178 @@ + + # Copyright 1992, Digital Equipment Corporation + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + # 008 17 Jun 1992 KDG/wbn Most of initial tailored version. (See + # commentary below.) + # + # 009 4 Jul 1992 KDG Continue work on initial tailored version, + # including bugfixes and mod entry points + # + # 010 15 Jul 1992 KDG - Final touches for V1 (other than any bugfixes) + # - .aligns commented out to allow older assembler versions + # + # 011 16 Jul 1992 KDG - Bugfix for ots_div_l for -maxint dividend + # - OSF-only source changes for BL7 + # + # 012 10 Aug 1992 KDG Fix overflow division entry points + # + # 013 23 Sep 1992 KDG Add case-sensitive entry names + # + # 014 4 Jan 1993 KDG Tweak for OSF assembler + # + # 015 26 Jan 1993 KDG Add underscore prefix, OSF uses CS names + # + # 016 5 Apr 1993 WBN Speed up core 64-bit, shrink table entry to 2 QWs + + #++ + # Entry points defined in this module: + # + # -- 32 bit division/remainder support + # unsigned ots_rem_ui(unsigned dividend, unsigned divisor) + # unsigned ots_div_ui(unsigned dividend, unsigned divisor) + # int ots_mod_i(int dividend, int modulus) + # int ots_rem_i(int dividend, int divisor) + # int ots_div_i_o(int dividend, int divisor) + # int ots_div_i(int dividend, int divisor) | "hot spot" + # {core routine - div32} | + # + # -- 64 bit division support + # {core routine - div64} | (uses div32 for 32b cases) + # long ots_div_l_o(long dividend, long divisor) + # long ots_div_l(long dividend, long divisor) | "hot spot" + # long ots_rem_l(long dividend, long divisor) + # long ots_mod_l(long dividend, long modulus) + # unsigned long ots_div_ul(unsigned long dividend, unsigned long divisor) + # unsigned long ots_rem_ul(unsigned long dividend, unsigned long divisor) + # + # Special conventions: No stack space, r0-r1, r16-r19 and r26-r28 ONLY. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # NOTE: This set of routines may start using stack space at some + # future point in time. + # + # -- Possible future entry points include: + # (These all return results in r0/r1) + # {int quotient, int remainder} ots_div_mod_i(int dividend, int divisor) + # {int quotient, int remainder} ots_div_mod_i_o(int dividend, int divisor) + # {int quotient, int remainder} ots_div_rem_i(int dividend, int divisor) + # {int quotient, int remainder} ots_div_rem_i_o(int dividend, int divisor) + # {unsigned quotient, unsigned remainder} ots_div_rem_ui(unsigned dividend, unsigned divisor) + # + # {long quotient, long remainder} ots_div_mod_i(long dividend, long divisor) + # {long quotient, long remainder} ots_div_mod_i_o(long dividend, long divisor) + # {long quotient, long remainder} ots_div_rem_i(long dividend, long divisor) + # {long quotient, long remainder} ots_div_rem_i_o(long dividend, long divisor) + # {unsigned long quotient, unsigned long remainder} + # ots_div_rem_ui(unsigned long dividend, unsigned long divisor) + # + # + # General commentary: + # + # This is an attempt at a fairly high performance version using relatively + # straightforward algorithms. Note that the code is intended to be scheduled + # well for EV4, but still reasonably for LCA/EV5. + # + # Also, note that there was only so much time available for this, so it + # is far from "perfect". "Better is the enemy of done"... + # + # Possible future areas of improvement (and unfinished business): + # + # - Another possible way of doing things for the "slow" (divnn cases) + # is to use an approximate inverse and convergence. Given the speed + # of the multiplier on EV4, and given "time to market", this wasn't + # done for V1.) I have some mail with the algorithm from Bob Gries + # (through Scott Robinson). + # + # - When the divisor is too large for the table, but has n low-order zero + # bits, see if divisor/2^n fits in the table, and use that entry with + # dividend/2^n + # + # - Use UMULH for the 'mod' routines. + # + # This version can do a table lookup division (divisors with <=tablesize) + # in roughly 32 cycles on an EV4 (with cache hits for all loads), of which + # 21 are for the umulh. There is a strong bias toward the table-lookup case. + # Note that for many cases, the umulh is the last thing before the return, + # so the multiply can occur in parallel with the procedure return. + # (It is interesting that the R3000 hardware divide instruction takes 33 + # cycles and the R4000 takes 76(!) ...) Small powers of 2 are retired in + # roughly 20 cycles. Larger divisors take considerably longer at this point. + # + +#include "ots_defs.hs" + +#ifdef OSF + # to get the PAL_gentrap literal +#include <alpha/pal.h> +#endif + + # Data area description + # + # The data area "ots_div_data" is an array of structures, indexed + # by the divisor value, with each array entry being 16 bytes in size + # formatted as follows: + # + # 6 + # 3 6 0 + # +-------+-------+-------+-------+-------+-------+-------+-------+ + # | 32 bit reciprocal (58 bits) |shift| + # +-------+-------+-------+-------+-------+-------+-------+-------+ + # | 64 bit reciprocal | + # +---------------------------------------------------------------+ + # + # The 64-bit reciprocal has the leading '1' bit omitted, so it provides + # 65 bits of precision -- enough to handle unsigned 64-bit values. + # + # The first longword contains the 6-bit shift amount needed to handle + # 64-bit cases and powers of two. + # + # The 32-bit reciprocal has the shift count built in, so a UMULH gives + # the correct quotient without shifting. The reciprocal needs 33 bits + # of precision. The 6-bit shift amount is noise in the reciprocal that + # can be ignored. + # + # (Oh, you want proof?) For divisors up to 2^k, we store k-1 leading + # zero bits, 33 bits of fraction, (25-k) more bits of fraction, and + # 6 bits of noise. The standard method would round at the 33rd fraction + # bit. We need to ensure that the value actually stored is geq the + # infinite reciprocal, but leq the standard value. For divisors up to + # 2^k, there will be a zero bit somewhere in the k bits below the 33rd, + # so as long as we round below the (33+k)th bit, the rounded value + # plus any noise is still less than the standard value. This requires + # k < 12. + # + # The actual data is declared in ots_div_data_alpha. + # + # Offsets to the various fields in the data structure + # +#define shift_o 0 +#define recip64_o 8 +#define recip32_o 0 + # + # Note that the shift/add ops used to compute the table entries + # "know" that the table size is 16. (i.e. addq -> s8addq -> ldq) + # By changing the first instruction, it's fairly easy to change the + # table entry size to 24, 32, or 40 bytes (using s4add/sub), or + # 56/64/72 bytes using s8add/sub, should that be desirable. + + # Maximum divisor present in the table + # +#define table_max 512 + + # Division by zero gentrap code + # +#define GEN_INTDIV -2 + + # Address of division data area (shared by all entry points) + # +#ifdef VMS + .psect ots_link +ots_div_addr: + .address ots_div_data + .psect ots_code +#endif + + # Dummy entry point for the module + # + .globl _OtsDivide + .ent _OtsDivide +_OtsDivide: + .set noat + .set noreorder +#ifdef OSF + .frame sp, 0, r26 +#endif +#ifdef WNT + .frame sp, 0, r26 +#endif + + + # unsigned ots_rem_ui(unsigned dividend, unsigned divisor) + # unsigned 32 bit remainder support + # + #.align 4 + .globl _OtsRemainder32Unsigned + .aent _OtsRemainder32Unsigned +_OtsRemainder32Unsigned: +#ifdef VMS + ldq r27, <ots_div_addr-ots_rem_ui>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + lda r28, -table_max(r17) # test for table lookup + subl r17, 1, r1 # first part of power-of-2 check + blt r17, rui_big # big divisors can (must) be handled by a simple comparison + and r17, r1, r18 # second part of power-of-2 check + bgt r28, rui_lrgdiv # branch if large divisor + addq r17, r17, r0 # compute divisor*2 for table lookup + beq r18, rui_pwr2 # if zero, divisor is a power of 2 + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + ldq r1, recip32_o(r27) # load approximate reciprocal + cmpult r16, r17, r18 # is the dividend < divisor? + zap r16, 0xF0, r0 # kill the propagated sign bit + bne r18, rui_lss # if dividend < divisor, fast exit + umulh r0, r1, r0 # multiplication for division step + mull r0, r17, r0 # multiply back to get value to subtract + subl r16, r0, r0 + ret r31, (r26) # and return + +rui_pwr2: + beq r17, divzer # check for 0 + and r16, r1, r0 # use x-1 to mask + ret r31, (r26) + +rui_lss: + mov r16, r0 + ret r31, (r26) + +rui_lrgdiv: + zap r16, 0xf0, r16 # zero-extend the dividend + bsr r28, div32 # use the core routine getting the remainder in r1 + sextl r1, r0 + ret r31, (r26) + + # divisors with the sign bit set. two possible results, + # dividend if dividend < divisor, or dividend-divisor otherwise +rui_big: + cmpult r16, r17, r1 + subl r16, r17, r0 + cmovne r1, r16, r0 + ret r31, (r26) + + + # unsigned ots_div_ui(unsigned dividend, unsigned divisor) + # unsigned 32 bit division support + # + + #.align 4 + .globl _OtsDivide32Unsigned + .aent _OtsDivide32Unsigned +_OtsDivide32Unsigned: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_ui>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + lda r28, -table_max(r17) # test for table lookup + blt r17, dui_big # big divisors can (must) be handled by a simple comparison + addq r17, r17, r18 # compute divisor*2 + cmpule r17, r16, r0 # is the dividend < divisor? + beq r17, divzer # check for 0 + s8addq r18, r27, r27 # finish computing table entry addr (table addr+divisor*16) + beq r0, dui_end # fast out for divisor > dividend + bgt r28, dui_lrgdiv # branch if large divisor + ldq r1, recip32_o(r27) # load approximate reciprocal + zap r16, 0xF0, r16 # kill the propagated sign bit + blt r1, dui_smpwr2 # go handle powers of 2 specially + umulh r16, r1, r0 # start multiplication for division step +dui_end:ret r31, (r26) # and return + nop +dui_smpwr2: + srl r16, r1, r0 # shift the result into place + sextl r0, r0 # reinsert sign if dividing by 1 + ret r31, (r26) # +dui_lrgdiv: + zap r16, 0xf0, r16 # zero-extend the dividend + bsr r28, div32 # use the core routine getting the remainder in r1 + sextl r0, r0 # make sure the result is in normal form for uint32 + ret r31, (r26) + + # divisor with the sign bit set. two possible results, + # 1 if divisor <= dividend, or 0 otherwise +dui_big: + cmpule r17, r16, r0 + ret r31, (r26) + + + # int ots_mod_i(int dividend, int modulus) + # signed 32 bit modulus support + # + # This entry could be MUCH more optimized. It doesn't even try to use + # UMULH division currently... (A casualty of time-to-market.) + # Note that mod is only used by Ada and PL/I. + # + #.align 4 + .globl _OtsModulus32 + .aent _OtsModulus32 +_OtsModulus32: + negq r17, r18 # first part of abs(divisor) + cmovge r17, r17, r18 # second part of abs(divisor) + subq r18, 1, r1 # start checking for power of 2 + beq r17, divzer # check for 0 + and r18, r1, r0 # second part of power-of-2 check + beq r0, mi_p2 # for powers of two, simply do a mask + # (note that the power-of-2 case MUST be used to handle + # the -maxint case due to the way the fix-up info is + # saved across the core routine call) + xor r16, r17, r28 # get xor of signs + clr r19 # don't need a bias if dividend and divisor have same sign + cmovlt r28, r17, r19 # bias is original divisor for different sign case + and r16, r17, r27 # if both dividend & divisor were neg. need to negate result + mov r18, r17 # move abs(divisor) into r17 + negq r16, r18 # first part of abs(dividend) + cmovlt r16, r18, r16 # second part of abs(dividend) + cmplt r27, r31, r0 # get 1 if both operands were <0 + sll r0, 63, r0 # get bit as the high bit + bis r0, r19, r19 # and MERGE with bias (0 -> no fixup, -maxint -> negate result, + # divisor > 0 - subtract remainder if non-zero, divisor < 0 - + # add remainder if non-zero) + bsr r28, div32 # use the core routine getting the remainder in r1 + cmoveq r1, r31, r19 # don't do any fix-up if the remainder was zero + addq r19, r19, r18 # check to see if this is the negative/negative case, which just gets a negated remainder + subq r19, 1, r28 # wrap -maxint to positive + negl r1, r0 # move negated value, may abort later + cmovlt r28, r1, r0 # if both positive, or negative divisor, keep positive remainder + cmoveq r18, r31, r19 # now that negation is done, treat -maxint case as 0 + addl r19, r0, r0 # add any bias (original divisor or 0) + ret r31, (r26) # and return + +mi_p2: cmovge r17, r31, r17 # no bias if divisor was >= 0 + and r16, r1, r1 # use the divisor-1 mask that's already in r1 + cmoveq r1, r31, r17 # use zero if result was zero + addl r17, r1, r0 # do any biasing, and ensure the result is sign ext + ret r31, (r26) # and return + + # int ots_rem_i(int dividend, int divisor) + # signed 32 bit remainder support + # + #.align 4 + .globl _OtsRemainder32 + .aent _OtsRemainder32 +_OtsRemainder32: +#ifdef VMS + ldq r27, <ots_div_addr-ots_rem_i>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + negq r17, r18 # first part of abs(divisor) + cmovlt r17, r18, r17 # second part of abs(divisor) + subq r17, 1, r1 # start checking for power of 2 + and r17, r1, r0 # finish check for power of 2 + sra r16, 63, r19 # get -1/0 if dividend was negative + negq r16, r18 # first part of abs(dividend) + cmovlt r16, r18, r16 # second part of abs(dividend) + beq r0, ri_pwr2 # for powers of two, simply do a mask (not power of 2 include 0 and 80000000) + lda r28, -table_max(r17) # test for table lookup + bgt r28, ri_lrgdiv # branch if large divisor + addq r17, r17, r0 # compute divisor*2 for table lookup + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + ldq r1, recip32_o(r27) # load approximate reciprocal + umulh r16, r1, r0 # multiplication for division step + mull r0, r17, r0 # multiply back to get value to subtract + subl r16, r0, r0 # get abs of final result + xor r0, r19, r0 # start compliment if original dividend was <0 + subl r0, r19, r0 # finish compliement + ret r31, (r26) # and return + + # Handle powers of 2, including 0 and 80000000 +ri_pwr2: + and r16, r1, r0 # use the divisor-1 mask in r1 + beq r17, divzer # division by zero + xor r0, r19, r0 # start compliment if original dividend was <0 + subl r0, r19, r0 # finish compliement + ret r31, (r26) + + nop +ri_lrgdiv: + bsr r28, div32 # use the core routine getting the remainder in r1 + xor r1, r19, r0 # start compliment if original dividend was <0 + subl r0, r19, r0 # finish compliement + ret r31, (r26) + + + # int ots_div_i_o(int dividend, int divisor) + # signed 32 bit division support, overflow detection + # + #.align 4 + .globl _OtsDivide32Overflow + .aent _OtsDivide32Overflow +_OtsDivide32Overflow: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_i_o>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + not r17, r1 # is the divisor -1? + bne r1, di_skip # continue if not + neglv r16, r0 # quotient = -dividend, overflow on ^x800000000 + ret r31, (r26) + + # int ots_div_i(int dividend, int divisor) + # signed 32 bit division support, no overflow detection + # + nop #.align 4 + .globl _OtsDivide32 + .aent _OtsDivide32 +_OtsDivide32: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_i>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif +di_skip: +di_retry: + lda r28, -table_max(r17) # test for table lookup + ble r17, di_notpos # not a positive divisor case + addq r17, r17, r0 # compute divisor*2 + negq r16, r18 # part 1 of abs(dividend) -> r18. (Note 0xffffffff 80000000 => 0x00000000 80000000) + bgt r28, di_lrgdiv # branch if large divisor + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + cmpule r17, r18, r0 # divisor <= dividend? + cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18 + beq r0, di_end # if not, result is zero + ldq r1, recip32_o(r27) # load approximate reciprocal + blt r1, di_smpwr2 # go handle powers of 2 specially + umulh r18, r1, r0 # start multiplication + blt r16, di_negres # negate result? (done as a branch to allow umulh to "hang out" over end for common case) +di_end: ret r31, (r26) # return for same-sign (common) case +di_negres: + negl r0, r0 # different signs - compliment result + ret r31, (r26) # return for different-sign (uncommon) case +di_smpwr2: + srl r18, r1, r18 # shift the result into place + sra r16, 63, r16 # get 0/-1 based on sign of dividend + xor r18, r16, r18 # conditionally compliment + subl r18, r16, r0 # and increment for the final value + ret r31, (r26) # (note subl is required for sign ext for %x80000000/1 case) + + # Zero or negative divisor case. If just a negative divisor, + # compliment both dividend and divisor and do things again. +di_notpos: + beq r17, divzer # division by zero + negl r17, r17 # |divisor|, note that 0x80000000 still appears negative + negq r16, r16 # compliment dividend (negq so that 0xffffffff 80000000 => 0x00000000 80000000 + bgt r17, di_retry # dispatch back for normal case (not 0x80000000 or 0) + sextl r16, r16 # + cmpeq r16, r17, r0 # -maxint/-maxint = 1, all others 0 + ret r31, (r26) # done + + # Large divisor for signed 32/32 case + # + nop #.align 3 +di_lrgdiv: + sra r16, 63, r19 # get 0/-1 based on sign of dividend + cmovlt r16, r18, r16 # + bsr r28, div32 # go use core routine + xor r0, r19, r0 # conditionally compliment + subl r0, r19, r0 # and increment for the final value (subl ensures normalized result) + ret r31, (r26) # done + + + # Large divisor case core routine for 32b + # (wbn) + # + # r0 - quotient (output) + # r1 - remainder (output) + # r16 - dividend (range 0..2^32-1, zero extended) + # r17 - divisor (range 1..2^31-1 - overwritten) + # r18 - scratch + # r19 - not used (one temp for 'caller') + # r26 - not used (expected to contain main return address) + # [r27 - scratch] (not currently written) + # r28 - this "subroutine" return address + # + # Some tightened up bit-at-a-time code for dividing 32-bit integers. + # It uses two tricks: keep the running remainder and the quotient in + # the same 64-bit register (MQ?), and add 1 while subtracting the divisor, + # so that a single CMOV sets both the new remainder and the new quotient. + # I start off by trying to skip 8 bits at a time; should this skip a + # smaller amount, so the main loop iterates less often? If the divisor + # is already known to be large enough, the last case in this test is never + # used... + # + # This code expects as input two integers in the range 0 <= x < 2^31 + # (that is, it doesn't work for general unsigned longwords, and doesn't + # include sign manipulation.) + # + # The code here takes about 34n+11 cycles for a quotient occupying n bytes. + # + # Inputs: dividend in r16, divisor in r17 + # Outputs: quotient in r0, remainder in r1 + # Destroys: [r16,]r17,r18,[r27] + # + # How many quotient bytes will there be: 0, 1, 2, 3, 4? + # + #.align 4 +div32: cmpule r17, r16, r0 # Divisor leq dividend? + sll r17, 32, r18 # Position divisor for loop + sll r17, 8, r1 # Prepare for next compare + beq r0, d32end # Dividend less, quotient is zero. +ediv32: mov 8-3, r17 # Hope to skip 3 bytes of loop + cmpule r1, r16, r0 # Shifted divisor still leq dividend? + sll r1, 8, r1 # Prepare for next compare + beq r0, d32ent # Go loop over just one byte + mov 8-2, r17 # Hope to skip 2 bytes of loop + cmpule r1, r16, r0 # Shifted divisor still leq dividend? + sll r1, 8, r1 # Prepare for next compare + beq r0, d32ent # Go loop over just two bytes + mov 8-1, r17 # Hope to skip 1 byte of loop + cmpule r1, r16, r0 # Shifted divisor still leq dividend? + nop # stall - align d32ent and d32loop + cmovne r0, 8, r17 # If we can't skip any bytes + + # start loop generating quotient bits. NOTE: The loop setup requires + # an even number of iterations. + # +d32ent: extqh r16, r17, r0 # Shift dividend left for skipped bytes + subq r18, 1, r1 # Divisor in high LW - 1 in low LW + s8subq r17, 34, r17 # Convert bytes to bits and adjust + + addq r0, r0, r0 # Shift left to start first iteration +d32loop:subq r0, r1, r18 # Can we subtract divisor from it? + cmovge r18, r18, r0 # If so, set new remainder & quotient + # stall + addq r0, r0, r0 # Shift remainder and quotient left + subq r0, r1, r18 # Can we subtract divisor from it? + cmovge r18, r18, r0 # If so, set new remainder & quotient + subq r17, 2, r17 # Loop counter + addq r0, r0, r0 # Shift remainder and quotient left + bgt r17, d32loop # Repeat + subq r0, r1, r18 # Can we subtract divisor from it? + cmovge r18, r18, r0 # If so, set new remainder & quotient + # stall + addq r0, r0, r0 # Shift remainder and quotient left + subq r0, r1, r18 # Finish last iteration + cmovge r18, r18, r0 + # stall + srl r0, 32, r1 # Get remainder in r1 + zap r0, 0xf0, r0 # Keep only quotient in r0 + nop # for alignment +d32end: cmoveq r0, r16, r1 # Move remainder to r1 for quotient=0 case + ret r31, (r28) # Not a real software procedure return + + + # Large divisor case core routine for 64b + # + # r0 - quotient (output) + # r1 - remainder (output) + # r16 - dividend (range 0..2^64-1 - overwritten) + # r17 - divisor (range 1..2^63-1 - overwritten) + # r18 - scratch + # r19 - not used (one temp for 'caller') + # r26 - not used (expected to contain main return address) + # r27 - points to table of inverses (overwritten) + # r28 - this "subroutine" return address + # + # Inputs: dividend in r16, divisor in r17 + # Outputs: quotient in r0, remainder in r1 + # Destroys: r16,r17,r18,r27 + # + # Note- this routine could save a few cycles if we could use + # another scratch register -- perhaps by pushing one on the stack? + # + #.align 4 +div64: sll r17, 32, r18 # Position for ediv32 + cmpule r17, r16, r0 # Is divisor leq dividend? + srl r17, 31, r1 # Is divisor geq 2^31? + beq r0, d64end # If divisor > dividend, quotient=0 + cmpule r18, r16, r0 # Is divisor*2^32 leq dividend? + sll r17, 8, r1 # Position for ediv32 checking + or r1, r0, r0 # 0 if divisor & quotient fit in 32 bits + beq r0, ediv32 # Use 32-bit routine if OK + + # Full 64-bit divide needed. Use the table of shift amounts to compute + # the number of leading zero bits in the divisor. Find the leftmost + # nonzero byte, then the leftmost nonzero bit in that byte. Table entry + # #n+1 contains the number of bits needed to hold n (1..8). We know the + # divisor is nonzero here. + # + cmpbge r31, r17, r0 # Get a zero bit for each nonzero byte + #stall + sll r0, 4, r0 # *16 bytes per table entry + #stall + subq r27, r0, r0 # table base plus complement... + #stall + ldq r1, 256*16(r0) # get position of first nonzero + #2 stalls + subq r1, 1, r1 # byte number of first nonzero + extbl r17, r1, r0 # get first nonzero byte + #stall + addq r0, r0, r0 # *2 + s8addq r0, r27, r0 # *16 bytes per table entry + #stall + ldq r0, 16(r0) # bit number of first nonzero + negq r1, r1 # 1 + #leading zero bytes (mod 8) + #stall + s8subq r1, r0, r0 # number of leading zero bits + and r0, 0x3F, r0 # discard other junk + + # The following code does a similar normalize calculation without the table. + #=== + # extll r17, #4, r18 ; Normalize the divisor and + # mov #63, r0 ; count leading zeros + # cmovne r18, #31, r0 + # cmoveq r18, r17, r18 + # ;stall + # extwl r18, #2, r1 + # ;stall + # cmovne r1, r1, r18 + # cmovne r1, #16, r1 + # ;stall + # subq r0, r1, r0 + # extbl r18, #1, r1 + # ;stall + # cmovne r1, r1, r18 + # cmovne r1, #8, r1 + # ;stall + # subq r0, r1, r0 + # andnot r18, #^x0f, r1 + # cmovne r1, r1, r18 + # cmovne r1, #4, r1 + # ;stall + # subq r0, r1, r0 + # andnot r18, #^x33, r1 + # cmovne r1, r1, r18 + # cmovne r1, #2, r1 + # ;stall + # subq r0, r1, r0 + # andnot r18, #^x55, r1 + # cmovne r1, #1, r1 + # ;stall + # subq r0, r1, r0 + #=== + + # R0 contains number of leading zero bits in the divisor. + + sll r17, r0, r17 # Normalize: MSB is set. + + # Now break divisor into pieces a+x, where a is the leading + # 9 bits, rounded, and x is the rest. Use a linear + # approximation for 1/divisor = 1/a - x/a^2 [+ x^2/a^3 -...] + # + srl r17, 64-10, r1 # Keep 10 bits of divisor + #stall + addq r1, 1, r1 # Round to form 'a' + andnot r1, 1, r1 + s8addq r1, r27, r27 # Index table of 1/a and 1/a^2 + sll r1, 64-10, r1 # shift 'a' to match divisor + ldq r18, (r27) # Load QW containing 1/a^2 + subq r1, r17, r1 # -x = a - divisor + beq r1, d64_easy # Use table directly if x=0 + inswl r18, 6, r18 # position 1/a^2 + blt r1, d64_sub # correct for sign of -x + umulh r1, r18, r1 # -x/a^2 + ldq r27, 8(r27) # Load QW containing 1/a - 1 + br r31, d64_cont + +d64_sub:umulh r1, r18, r1 # -x/a^2 + ldq r27, 8(r27) # load QW containing 1/a - 1 + # 2 stalls + s4addq r18, 0, r18 + subq r27, r18, r27 # correct for sign of -x +d64_cont: + # many stalls + s4addq r1, r27, r18 # 1/divisor approx= 1/a - x/a^2 + + # Now one or two Newton iterations to get 24 or 56 good bits of the inverse. + # Each computes inv = inv * (2 - inv*divisor). We could skip out early + # here or above if the dividend and/or quotient is small enough for the + # amount of precision we've developed... + # + # We handle quadwords with the radix point on the left. The divisor has + # been normalized to the range 0.5 < divisor < 1.0; the inverses are in + # the range 1.0 < inverse < 2.0, and are represented without the leading 1. + # + umulh r18, r17, r1 # (inv0 - 1) * divisor + # many stalls + addq r1, r17, r1 # add hidden bit * divisor + negq r1, r1 # 2 - inv0*divisor, very near 1.0 + umulh r18, r1, r27 # (inv0 - 1) * (2 - inv0*divisor) + cmovlt r1, 0, r18 # keep inv0 if (2-inv0*divisor) > 1.0 + #stall + addq r18, r1, r1 # add it to hidden bit * (2-inv0*divisor) + # many stalls + addq r27, r1, r18 # inv1 = inv0 * (2 - inv0*divisor) + + umulh r18, r17, r1 # (inv1 - 1) * divisor + # many stalls + addq r1, r17, r1 # add hidden bit * divisor + negq r1, r1 # 2 - inv1*divisor, very near 1.0 + umulh r18, r1, r27 # (inv1 - 1) * (2 - inv1*divisor) + cmovlt r1, 0, r18 # keep inv1 if (2-inv1*divisor) > 1.0 + addq r18, r1, r1 # add it to hidden bit * (2-inv1*divisor) + # many stalls + addq r27, r1, r1 # inverse = inv1 * (2 - inv1*divisor) + umulh r1, r16, r18 # dividend * (1/divisor - 1) + srl r17, r0, r17 # un-normalize divisor + negq r0, r0 + subq r0, 8, r0 # how far right after first byte + # many stalls + addq r18, r16, r18 # add hidden bit * dividend + cmpult r18, r16, r1 # did it carry? + srl r18, 8, r18 # start to shift + sll r1, 56, r1 # position the carry + #stall + addq r1, r18, r1 # add the carry + srl r1, r0, r0 # final shift + mulq r17, r0, r1 # try out this quotient + # many stalls + subq r16, r1, r1 # form remainder + cmpule r17, r1, r18 # must be less than divisor + subq r1, r17, r27 + cmovne r18, r27, r1 # if not, decrement remainder + addq r0, r18, r0 # and increment quotient + ret r31, (r28) # done + +d64_easy: + ldq r1, 8(r27) # get 1/divisor, except hidden bit + srl r17, r0, r17 # un-normalize divisor again + blt r18, d64_pow2 # skip if power of 2 + umulh r1, r16, r18 # dividend/divisor + negq r0, r0 # how far right to shift + and r16, 0x0ff, r1 # pieces of dividend + subq r0, 8, r0 # how far right after first byte + srl r16, 8, r27 + # many stalls + addq r18, r1, r1 # add low piece of dividend, no carry + srl r1, 8, r1 # make room for high piece + #stall + addq r1, r27, r1 # finish adding hidden bit * dividend + srl r1, r0, r0 # final shift + mulq r17, r0, r1 # need to compute remainder too + # many stalls + subq r16, r1, r1 + ret r31, (r28) # done + +d64_pow2: + not r0, r0 # how far right to shift quotient + subq r17, 1, r1 # mask for remainder + srl r16, r0, r0 # shift for quotient + and r16, r1, r1 # get remainder + ret r31, (r28) # done + +d64end: mov r16, r1 # Remainder to r1 for small quotient case + ret r31, (r28) # Not a real software procedure return + + # long ots_div_l_o(long dividend, long divisor) + # signed 64 bit division support, overflow detection + # + #.align 4 + .globl _OtsDivide64Overflow + .aent _OtsDivide64Overflow +_OtsDivide64Overflow: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_l_o>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + not r17, r1 # is the divisor -1? + bne r1, dl_skip # continue if not + negqv r16, r0 # q = -dividend, oflow on ^x800000000 00000000 + ret r31, (r26) + nop + + # long ots_div_l(long dividend, long divisor) + # signed 64 bit division support, no overflow detection + # + .globl _OtsDivide64 + .aent _OtsDivide64 +_OtsDivide64: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_l>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif +dl_skip: + xor r16, r17, r19 # sign bit = result needs to be complimented (here to handle -maxint correctly) +dl_retry: + lda r28, -table_max(r17) # test for table lookup + ble r17, dl_notpos # not a positive divisor case + addq r17, r17, r0 # compute divisor*2 + negq r16, r18 # part 1 of abs(dividend) -> r18 + bgt r28, dl_lrgdiv # branch if large divisor + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + srl r16, 33, r1 # can this be handled via a 32 bit case? + cmpule r17, r18, r0 # divisor <= dividend? + bne r1, dl_64bit # does this need to be a real 64 bit case? + cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18 + beq r0, dl_end # if not, result is zero + ldq r27, recip32_o(r27) # load 32b approximate reciprocal + sra r19, 63, r19 # get 0/-1 + blt r27, dl_smpwr2 # skip umulh for powers of 2 specially + umulh r18, r27, r0 # start multiplication + beq r19, dl_end # if compliment not required, let umulh "hang out" + negq r0, r0 # compliment case + ret r31, (r26) # +dl_64bit: + cmovge r16, r16, r18 # part 2 abs. val of the dividend -> r18 + beq r0, dl_end # if not, result is zero + ldq r1, recip64_o(r27) # load approximate reciprocal + sra r19, 63, r19 # get 0/-1 + ldq r27, shift_o(r27) # load shift count (low 6 bits are all that matters) + beq r1, dl_smpwr2 # skip umulh for powers of 2 specially + umulh r18, r1, r0 # start multiplication + addq r0, r18, r18 # add hidden bit +dl_smpwr2: + srl r18, r27, r18 # shift the result into place + xor r18, r19, r18 # conditionally compliment + subq r18, r19, r0 # and increment for the final value +dl_end: ret r31, (r26) # + + # Zero or negative divisor case. If just a negative divisor, + # compliment both dividend and divisor and do things again. +dl_notpos: + beq r17, divzer # division by zero + negq r17, r17 # |divisor|, note that 0x80000000 00000000 still appears negative + negq r16, r16 # compliment dividend + bgt r17, dl_retry # dispatch back for normal case (not 0x80000000 00000000 or 0) + cmpeq r16, r17, r0 # -maxint/-maxint = 1, all others 0 + ret r31, (r26) # done + + # Large divisor for signed 64/64 case + # +dl_lrgdiv: + sra r19, 63, r19 # get 0/-1 + cmovlt r16, r18, r16 # + bsr r28, div64 # go use core routine + xor r0, r19, r0 # conditionally compliment + subq r0, r19, r0 # and increment for the final value + ret r31, (r26) # done + + + # long ots_rem_l(long dividend, long divisor) + # signed 64 bit remainder support + # + #.align 4 + .globl _OtsRemainder64 + .aent _OtsRemainder64 +_OtsRemainder64: +#ifdef VMS + ldq r27, <ots_div_addr-ots_rem_l>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + negq r17, r18 # first part of abs(divisor) + cmovlt r17, r18, r17 # second part of abs(divisor) + subq r17, 1, r1 # start checking for power of 2 + and r17, r1, r0 # finish check for power of 2 + sra r16, 63, r19 # get -1/0 if dividend was negative + negq r16, r18 # first part of abs(dividend) + cmovlt r16, r18, r16 # second part of abs(dividend) + beq r0, rl_pwr2 # for powers of two, simply do a mask (not power of 2 include 0 and 80000000) + lda r28, -table_max(r17) # test for table lookup + bgt r28, rl_lrgdiv # branch if large divisor + addq r17, r17, r0 # compute divisor*2 for table lookup + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + ldq r1, recip64_o(r27) # load approximate reciprocal + ldq r18, shift_o(r27) # load shift amount + umulh r16, r1, r0 # multiplication for division step + addq r0, r16, r0 # add hidden bit + srl r0, r18, r0 + mulq r0, r17, r0 # multiply back to get value to subtract + subq r16, r0, r0 # get abs of final result + xor r0, r19, r0 # start compliment if original dividend was <0 + subq r0, r19, r0 # finish compliement + ret r31, (r26) # and return + + # Handle powers of 2, including 0 and 80000000 00000000 +rl_pwr2: + negq r16, r18 # first part of abs(dividend) + cmovlt r16, r18, r16 # second part of abs(dividend) + and r16, r1, r0 # use the divisor-1 mask in r1 + beq r17, divzer # division by zero + xor r0, r19, r0 # start compliment if original dividend was <0 + subq r0, r19, r0 # finish compliement + ret r31, (r26) + +rl_lrgdiv: + bsr r28, div64 # use the core routine getting the remainder in r1 + xor r1, r19, r0 # start compliment if original dividend was <0 + subq r0, r19, r0 # finish complement + ret r31, (r26) + + # long ots_mod_l(long dividend, long modulus) + # signed 64 bit modulus support + # + # This entry could be MUCH more optimized. It doesn't even try to use + # UMULH division currently... (A casualty of time-to-market.) + # Note that mod is only used by Ada and PL/I. + # + #.align 4 + .globl _OtsModulus64 + .aent _OtsModulus64 +_OtsModulus64: +#ifdef VMS + ldq r27, <ots_div_addr-ots_rem_l>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + negq r17, r18 # first part of abs(divisor) + cmovge r17, r17, r18 # second part of abs(divisor) + subq r18, 1, r1 # start checking for power of 2 + beq r17, divzer # check for 0 + and r18, r1, r0 # second part of power-of-2 check + beq r0, ml_p2 # for powers of two, simply do a mask + # (note that the power-of-2 case MUST be used to handle + # the -maxint case due to the way the fix-up info is + # saved across the core routine call) + xor r16, r17, r28 # get xor of signs + clr r19 # don't need a bias if dividend and divisor have same sign + cmovlt r28, r17, r19 # bias is original divisor for different sign case + and r16, r17, r28 # if both dividend & divisor were neg. need to negate result + mov r18, r17 # move abs(divisor) into r17 + negq r16, r18 # first part of abs(dividend) + cmovlt r16, r18, r16 # second part of abs(dividend) + cmplt r28, r31, r0 # get 1 if both operands were <0 + sll r0, 63, r0 # get bit as the high bit + bis r0, r19, r19 # and MERGE with bias (0 -> no fixup, -maxint -> negate result, + # divisor > 0 - subtract remainder if non-zero, divisor < 0 - + # add remainder if non-zero) + bsr r28, div64 # use the core routine getting the remainder in r1 + cmoveq r1, r31, r19 # don't do any fix-up if the remainder was zero + addq r19, r19, r18 # check to see if this is the negative/negative case, which just gets a negated remainder + subq r19, 1, r28 # wrap -maxint to positive + negq r1, r0 # move negated value, may abort later + cmovlt r28, r1, r0 # if both positive, or negative divisor, keep positive remainder + cmoveq r18, r31, r19 # now that negation is done, treat -maxint case as 0 + addq r19, r0, r0 # add any bias (original divisor or 0) + ret r31, (r26) # and return + +ml_p2: cmovge r17, r31, r17 # no bias if divisor was >= 0 + and r16, r1, r1 # use the divisor-1 mask that's already in r1 + cmoveq r1, r31, r17 # use zero if result was zero + addq r17, r1, r0 # do any biasing + ret r31, (r26) # and return + + + # unsigned long ots_div_ul(unsigned long dividend, unsigned long divisor) + # unsigned 64 bit division support + # + nop #.align 4 + .globl _OtsDivide64Unsigned + .aent _OtsDivide64Unsigned +_OtsDivide64Unsigned: +#ifdef VMS + ldq r27, <ots_div_addr-ots_div_ul>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + lda r28, -table_max(r17) # test for table lookup + blt r17, dul_big # big divisors can (must) be handled by a simple comparison + addq r17, r17, r18 # compute divisor*2 + srl r16, 33, r19 # can this be handled via the fast path for 31 bit dividends? + beq r17, divzer # check for 0 + s8addq r18, r27, r18 # finish computing table entry addr (table addr+divisor*16) + bgt r28, dul_lrgdiv # branch if large divisor + cmpule r17, r16, r0 # is the dividend < divisor? + bne r19, dul_64bit # if the dividend doesn't fit in 31 bits, use the larger umulh form + ldq r27, recip32_o(r18) # load approximate 32b reciprocal & shift count + beq r0, dul_end # fast out for divisor > dividend + blt r27, dul_smpwr2 # go handle powers of 2 specially + umulh r16, r27, r0 # 32b recip + ret r31, (r26) # + + # the 64 bit case is at a disadvantage to the 32b case because it needs + # a fix-up at the end, which prevents the latency of the umulh from + # being partially absorbed by the procedure return and anything that + # immediately follows that doesn't interlock. + nop +dul_64bit: + ldq r1, recip64_o(r18) # load approximate 64b reciprocal + ldq r27, shift_o(r18) # load shift count (low 6 bits are all that matters) + beq r0, dul_end # fast out for divisor > dividend + beq r1, dul_smpwr2 # go handle powers of 2 specially + umulh r16, r1, r0 # start multiplication for division step + zap r16, 0x0f, r18 # split dividend into two parts + zapnot r16, 0x0f, r16 + srl r18, r27, r18 # position the high part + addq r0, r16, r0 # add hidden * low dividend (no carry) + srl r0, r27, r0 # shift into place + addq r0, r18, r0 # add hidden * high dividend + ret r31, (r26) + +dul_smpwr2: + srl r16, r27, r0 # shift the result into place +dul_end: ret r31, (r26) # + +dul_lrgdiv: + bsr r28, div64 # use the core routine + ret r31, (r26) + + # divisor with the sign bit set. two possible results, + # 1 if divisor <= dividend, or 0 otherwise +dul_big: + cmpule r17, r16, r0 + ret r31, (r26) + + + # long unsigned ots_rem_ul(long unsigned dividend, long unsigned divisor) + # unsigned 64 bit remainder support + # + #.align 4 + .globl _OtsRemainder64Unsigned + .aent _OtsRemainder64Unsigned +_OtsRemainder64Unsigned: +#ifdef VMS + ldq r27, <ots_div_addr-ots_rem_ul>(r27)# start loading address of division data area +#endif +#ifdef OSF + ldgp gp, 0(r27) # load the global pointer + .frame sp, 0, r26 + lda r27, _OtsDivData # start loading address of the division data area +#endif +#ifdef WNT + .frame sp, 0, r26 + lda r27, _OtsDivData # load the division data table address +#endif + lda r28, -table_max(r17) # test for table lookup + subq r17, 1, r1 # first part of power-of-2 check + blt r17, rul_big # big divisors can (must) be handled by a simple comparison + and r17, r1, r18 # second part of power-of-2 check + bgt r28, rul_lrgdiv # branch if large divisor + addq r17, r17, r0 # compute divisor*2 for table lookup + beq r18, rul_pwr2 # if zero, divisor is a power of 2 + s8addq r0, r27, r27 # finish computing table entry addr (table addr+divisor*16) + ldq r1, recip64_o(r27) # load approximate reciprocal + cmpult r16, r17, r18 # is the dividend < divisor? + bne r18, rul_lss # if so, fast exit + ldq r19, shift_o(r27) # load the shift count + umulh r16, r1, r0 # multiplication for division step + blt r16, rul_carry # careful handling if >= 2^63 + addq r0, r16, r0 # add hidden bit * dividend + srl r0, r19, r0 + mulq r0, r17, r0 # multiply back to get value to subtract + subq r16, r0, r0 + ret r31, (r26) # and return + +rul_carry: + zap r16, 0x0f, r18 # split dividend into two parts + zapnot r16, 0x0f, r1 + srl r18, r19, r18 # position the high part + addq r0, r1, r0 # add hidden * low dividend (no carry) + srl r0, r19, r0 # shift into place + addq r0, r18, r0 # add hidden * high dividend + mulq r0, r17, r0 # multiply back to get value to subtract + subq r16, r0, r0 + ret r31, (r26) + +rul_pwr2: + beq r17, divzer # check for 0 + and r16, r1, r0 # use x-1 to mask + ret r31, (r26) + +rul_lss: + mov r16, r0 + ret r31, (r26) + + # divisors with the sign bit set. two possible results, + # dividend if dividend < divisor, or dividend-divisor otherwise +rul_big: + cmpult r16, r17, r1 + subq r16, r17, r0 + cmovne r1, r16, r0 + ret r31, (r26) + + nop +rul_lrgdiv: + bsr r28, div64 # use the core routine getting the remainder in r1 + mov r1, r0 # return remainder as the result in r0 + ret r31, (r26) + + + # Division-by-zero handling + # (forward branch from all routines, out of the way here as well.) + # +divzer: lda r16, GEN_INTDIV(r31) # load GENTRAP code for division by zero + clr r0 # return 0 for the result + clr r1 # +#ifdef VMS + gentrap # signal the error +#endif +#ifdef OSF + call_pal PAL_gentrap +#endif +#ifdef WNT + # Since I couldn't find this in a header file anywhere for NT... +#define PAL_gentrap 0xaa + call_pal PAL_gentrap +#endif + ret r31, (r26) # return (in case someone tries to continue) + + .set at + .set reorder + .end _OtsDiv diff --git a/private/crt32/misc/alpha/otsjmp.s b/private/crt32/misc/alpha/otsjmp.s new file mode 100644 index 000000000..9c49751f9 --- /dev/null +++ b/private/crt32/misc/alpha/otsjmp.s @@ -0,0 +1,117 @@ +// TITLE("Set Jump") +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// otsjmp.s +// +// Abstract: +// +// This module implements the Alpha C8/GEM C compiler specific routine to +// perform a setjmp. +// +// N.B. This module conditionally provides UNSAFE handling of setjmp and +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an uninitialized variable +// has been set to a nonzero value. +// +// Author: +// +// Thomas Van Baak (tvb) 22-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + +// +// Define variable that will cause setjmp/longjmp to be safe or unsafe with +// respect to structured exception handling. +// + + .globl _Otssetjmpexused + .comm _Otssetjmpexused, 4 + + SBTTL("Set Jump - GEM version") +//++ +// +// int +// _Otssetjmp3 ( +// IN OUT jmp_buf JumpBuffer, +// IN PVOID RealFramePointer, +// IN PVOID SebPointer +// ) +// +// Routine Description: +// +// This function saves the current nonvolatile register state in the +// specified jump buffer and returns a function value of zero. +// +// N.B. The name `_Otssetjmp3' was chosen to avoid collision with an +// earlier implementation named _Otssetjmp. This version has three +// arguments. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// RealFramePointer (a1) - Supplies the real frame pointer value. +// +// SebPointer (a2) - Supplies the pointer to the current SEB or NULL +// if the call was made outside of any SEH scope. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + LEAF_ENTRY(_Otssetjmp3) + + ldl v0, _Otssetjmpexused // get value of switch variable + bne v0, 10f // if ne, provide safe setjmp + +// +// Provide unsafe handling of setjmp. +// + + stt f2, JbFltF2(a0) // save floating registers f2 - f9 + stt f3, JbFltF3(a0) // + stt f4, JbFltF4(a0) // + stt f5, JbFltF5(a0) // + stt f6, JbFltF6(a0) // + stt f7, JbFltF7(a0) // + stt f8, JbFltF8(a0) // + stt f9, JbFltF9(a0) // + + stq s0, JbIntS0(a0) // save integer registers s0 - s6/fp + stq s1, JbIntS1(a0) // + stq s2, JbIntS2(a0) // + stq s3, JbIntS3(a0) // + stq s4, JbIntS4(a0) // + stq s5, JbIntS5(a0) // + stq fp, JbIntS6(a0) // + + ldil t0, 1 // get unsafe setjmp flag + stl t0, JbType(a0) // set jump buffer context type + stq sp, JbIntSp(a0) // save stack pointer + stq ra, JbFir(a0) // get setjmp return address + + mov zero, v0 // set zero return value + ret zero, (ra) // return + +// +// Provide safe handling of setjmp. +// + +10: jmp zero, (v0) // finish in _setjmpex code + + .end _Otssetjmp3 diff --git a/private/crt32/misc/alpha/otsjmpex.s b/private/crt32/misc/alpha/otsjmpex.s new file mode 100644 index 000000000..eaf78190b --- /dev/null +++ b/private/crt32/misc/alpha/otsjmpex.s @@ -0,0 +1,84 @@ +// TITLE("Set Jump Extended") +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// otsjmpex.s +// +// Abstract: +// +// This module implements the Alpha C8/GEM C compiler specific routine to +// provide SAFE handling of setjmp/longjmp with respect to structured +// exception handling. +// +// Author: +// +// Thomas Van Baak (tvb) 22-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + +// +// Define variable that will cause setjmp/longjmp to be safe with respect +// to structured exception handling. +// + + .globl _Otssetjmpexused + .data +_Otssetjmpexused: + .long _Otssetjmpex3 // set address of safe setjmp routine + + SBTTL("Set Jump Extended - GEM version") +//++ +// +// int +// _Otssetjmpex3 ( +// IN OUT jmp_buf JumpBuffer, +// IN PVOID RealFramePointer, +// IN PVOID SebPointer +// ) +// +// Routine Description: +// +// This function implements a safe setjmp. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// RealFramePointer (a1) - Supplies the real frame pointer value. +// +// SebPointer (a2) - Supplies the pointer to the current SEB or NULL +// if the call was made outside of any SEH scope. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + LEAF_ENTRY(_Otssetjmpex3) + +// +// Save the given set jump context in the jump buffer. +// + + stl a1, JbFp(a0) // save real frame pointer + stl ra, JbPc(a0) // save target instruction address + stl a2, JbSeb(a0) // save SEB pointer + ldil t0, 3 // get GEM safe setjmp flag + stl t0, JbType(a0) // set jump buffer context type + mov zero, v0 // set return value + ret zero, (ra) // return + + .end _Otssetjmpex3 diff --git a/private/crt32/misc/alpha/otsnote.txt b/private/crt32/misc/alpha/otsnote.txt new file mode 100644 index 000000000..af99f6697 --- /dev/null +++ b/private/crt32/misc/alpha/otsnote.txt @@ -0,0 +1,115 @@ +Alpha AXP MSCGEM OTS C run-time library notes. + +- The following OTS source files were obtained from Kent Glossop on + 27-Jan-1993. I believe the version number is X1.0-4. + + div.s + divdat.s + + extv.s + extvvol.s + extzv.s + extzvvol.s + + insv.s + insvvol.s + + ots_as.hs + ots_defs.hs + + scmpeql.s + scmpeqlp.s + scmpleq.s + scmpleqp.s + scmplss.s + scmplssp.s + + sfill.s + sloc.s + smove.s + smovem.s + strans.s + szero.s + +- The six strcmp/cpy/len functions were obtained through Rich Peterson + on 25-Jan-1993. + + strcmp.s + strcmp_.s + strcpy.s + strcpy_.s + strlen.s + strlen_.s + +- For now, and in the interest of maintenance, we have left the source + files intact in spite of the fact that they don't follow conventions + of all other NT/Alpha assembler code. + +- The following files had a non-ascii 0xa9 character instead of a (c) + in the copyright line. These have been fixed so slm works right. + + scmpeql.s + scmpeqlp.s + scmpleq.s + scmpleqp.s + scmplss.s + scmplssp.s + sloc.s + strans.s + +- The goal is to provide compatible C runtime support for both acc and + GEM compilers through the existing NT C libraries. + +- Both compilers, header files, runtime libraries, and object files are + compatible with each other now, with these exceptions: + + o The setjmp/longjmp functions are not compatible since the data in + the jump buffer differs between the two compilers. SEH is 100% + compatible, however. + + o Calls to setjmp would actually work with acc even if setjmp.h was + not included. With GEM, the include file is required for proper + operation. + + o As of 930205, small structures are still passed and returned by + value incompatibly between the two compilers. This will be fixed + by upgrading acc to follow the GEM calling standard, and/or by + using a GEM switch to be acc compatible. + + o The above is not quite correct: as of 930217, GEM is using an option + to follow the acc convention, not the calling standard convention. + It looks like both acc and GEM will have options to handle small + structures both ways. + +- The str functions will conflict with the portable versions in the + ..\string directory. The portable ones should be #ifdef'ed out for + Alpha. + +- The two or three different versions of divide routines may get + sorted out later when we have a chance to do better performance + work. + +- A _OtsUnwindRfp was added to jmpuwind.s. This may not be used by GEM/C, + but will be used by GEM/Pascal. + +930728 + +- _OtsUnwindRfp is permanent and is also used by C for gotos out of finally + handlers and by the GEM C specific handler function. All DLLs that exported + RtlUnwind now also export RtlUnwindRfp. + +- Both compilers pass and return small structures in registers. This change + was made some months ago. The object file magic number was changed at the + same time to eliminate any calling standard mismatch. + +- The contents of the jump buffer is not the same between the two compilers + but a jump buffer type field is set by setjmp and there is only one longjmp + function so there are now no interoperability problems between the two + compilers. + +- A new set of OTS source files was obtained from Patsy Griffin on 1-Jun-1993. + The version number is V1.0. The only changes are in div.s (renamed otsdiv.s + for NT) and divdat.s. These implement a faster division algorithm, similar + to the one already used in fastdiv.s for acc. + +tvb diff --git a/private/crt32/misc/alpha/otsuwind.s b/private/crt32/misc/alpha/otsuwind.s new file mode 100644 index 000000000..c53a511fa --- /dev/null +++ b/private/crt32/misc/alpha/otsuwind.s @@ -0,0 +1,80 @@ +// TITLE("Jump to Unwind") +//++ +// +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// otsuwind.s +// +// Abstract: +// +// This module implements the Alpha C8/GEM compiler specific routine to +// jump to the runtime library unwind routine. +// +// Author: +// +// Thomas Van Baak (tvb) 30-Apr-1992 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + + SBTTL("Jump to Unwind - GEM version") +//++ +// +// VOID +// _OtsUnwindRfp ( +// IN PVOID TargetRealFrame OPTIONAL, +// IN PVOID TargetPc OPTIONAL, +// IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, +// IN PVOID ReturnValue +// ) +// +// Routine Description: +// +// This function transfers control to unwind. It is used by the GEM +// compiler when a non-local goto occurs and structured exception handling +// is not involved. The unwind routine called is the variant that expects +// a real frame pointer instead of the usual virtual frame pointer. +// +// Arguments: +// +// TargetRealFrame (a0) - Supplies an optional pointer to the call frame +// that is the target of the unwind. If this parameter is not specified, +// then an exit unwind is performed. +// +// TargetPc (a1) - Supplies an optional target instruction address where +// control is to be transferred to after the unwind operation is +// complete. This address is ignored if the target frame parameter is +// not specified. +// +// ExceptionRecord (a2) - Supplies an optional pointer to an exception +// record. +// +// ReturnValue (a3) - Supplies a value that is to be placed in the integer +// function return register just before continuing execution. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(_OtsUnwindRfp) + +// +// All four arguemnts are the same as those required by unwind. Just jump to +// the unwind function. This thunk is necessary to avoid name space pollution. +// The compiler should not generate a call directly to RtlUnwindRfp. +// + + br zero, RtlUnwindRfp // unwind to specified target + + .end _OtUnwindRfp diff --git a/private/crt32/misc/alpha/scmpeql.s b/private/crt32/misc/alpha/scmpeql.s new file mode 100644 index 000000000..2d9f82fcc --- /dev/null +++ b/private/crt32/misc/alpha/scmpeql.s @@ -0,0 +1,295 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_eqls(char *str1, long strlen, char *str2); + # compares two strings of the same length. + # returns r0=1 if str1=str2, r0=0 otherwise. + + # long ots_strcmp_eql(char *str1, long str1len, char *str2, long str2len); + # compares two strings of different lengths, without padding. + # returns r0=1 if str1=str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r21 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004 + # + # 006 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 007 22 Sep 1992 KDG Add case-sensitive name + # + # 008 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = len + # r18 --> B + # returns r0=1 if equal, r0=0 if not equal + # destroys r16-r21, r27-r28 + + #.align octa + .globl _OtsStringCompareEqlSameLen + .ent _OtsStringCompareEqlSameLen +_OtsStringCompareEqlSameLen: + .set noat + .set noreorder + .frame sp,0,r26 + subq r17, 8, r19 # More than 8 bytes to compare? + beq r17, equal # Done if empty strings + +join: ldq_u r20, (r16) # Get first QW containing part of A + addq r18, r17, r27 # Point to end of B + + ldq_u r21, (r18) # Get first QW containing part of B + bgt r19, big # Skip if more than 8 bytes + + ldq_u r27, -1(r27) # Get last QW containing part of B + addq r16, r17, r28 # Point to end of A + + extql r20, r16, r20 # Get first part of A + + ldq_u r28, -1(r28) # Get last QW containing part of A + + extql r21, r18, r21 # Get first part of B + + extqh r27, r18, r27 # Get last part of B + + extqh r28, r16, r28 # Get last part of A + + or r21, r27, r27 # Combine B + + or r20, r28, r28 # Combine A + + xor r28, r27, r0 # Are they different? + + extqh r0, r19, r0 # Discard differences after length + + nop + + cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not + ret r31, (r26) + +equal: mov 1, r0 # Return true + ret r31, (r26) + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # returns r0=1 if equal, r0=0 if not equal + # destroys r16-r21, r27-r28 + # + nop #.align octa + nop + + .globl _OtsStringCompareEql + .aent _OtsStringCompareEql +_OtsStringCompareEql: + .frame sp,0,r26 + cmpeq r17, r19, r0 # Are lengths equal? + beq r17, done # If one is zero, no compares needed + + subq r17, 8, r19 # More than 8 bytes to compare? + blbs r0, join # Only compare if lengths equal + +done: ret r31, (r26) # Return result of length comparison + + #.odd +big: and r16, 7, r0 # A alignment, or amount not compared + + subq r18, r0, r18 # Back up B pointer that much + + and r18, 7, r17 # Is B now aligned? + + addq r19, r0, r19 # (Len-8+align) is amount left to do + ldq_u r27, 8(r18) # Get next QW of B + + subq r19, 16, r19 # More than 2 QW's left? + bne r17, unalign # Skip if B alignment doesn't match + + xor r20, r21, r0 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r0, r16, r0 # Discard junk preceding strings + ble r19, bottom # Skip if two quadwords or less to go + + # stall + +loop: ldq_u r20, 16(r16) # Get yet another QW of A + bne r0, not_eq # Done if difference in prior compare + + xor r28, r27, r0 # Compare prior QW's + ldq r21, 16(r18) # Get yet another QW of B + + subq r19, 16, r19 # Decrement length + bne r0, not_eq # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r20, r21, r0 # Compare QW's loaded at top of loop + bgt r19, loop # Repeat until two or less QWs left + +bottom: addq r19, 8, r19 # More than 1 QW left? + bne r0, not_eq # Done if difference in prior compare + + xor r28, r27, r0 # Compare QW's just loaded + ble r19, last # Skip if this is last compare + + ldq_u r28, 16(r16) # Get last QW of A + bne r0, not_eq # Done if difference in this compare + + ldq r27, 16(r18) # Get last QW of B + + #2 stalls + + xor r28, r27, r0 # Compare last QW's + +last: extqh r0, r19, r0 # Discard diffs after length + + nop + + cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not + ret r31, (r26) + + #.align quad +unalign: + extql r21, r18, r21 # Get first part of B + + extqh r27, r18, r0 # Get second part of B + + #stall + + or r0, r21, r21 # Combine pieces of B + + xor r20, r21, r0 # Compare with A + + mskqh r0, r16, r0 # Trim junk preceding strings + blt r19, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r21, 16(r18) # Get more B + subq r19, 16, r19 # Decrement length + + extql r27, r18, r17 # Get piece of B from prior QW + bne r0, not_eq # Done if r1.ne.r2 + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r21, r18, r0 # Get piece of B from first QW in loop + + ldq_u r20, 16(r16) # Get still more A + extql r21, r18, r21 # Get second piece of B from there + + or r17, r0, r17 # Combine pieces for first B + + xor r28, r17, r0 # Compare with first A + + extqh r27, r18, r17 # Start building second B + bne r0, not_eq # Done if r28.ne.r17 + + addq r16, 16, r16 # Increment A pointer + + or r17, r21, r21 # Combine pieces for second B + + xor r20, r21, r0 # Compare with second A + bge r19, loop_u # Repeat if at least 16 more bytes + +bott_u: and r19, 8, r17 # At least 8 more bytes? + bne r0, not_eq # Done if r1.ne.r2 + + and r19, 7, r19 # How many odd bytes? + beq r17, last_u # Skip if not a whole QW + + extql r27, r18, r17 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r0 # Get a piece of new B QW + + #stall + + or r17, r0, r17 # Combine pieces + + xor r28, r17, r0 # Compare with A + + nop + bne r0, not_eq # Done if r28.ne.r17 + +last_u: addq r18, r19, r17 # Point to end of B + beq r19, eql_u # Return true if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + + ldq_u r20, 7(r17) # Get QW containing end of B + + extql r27, r18, r27 # Get piece of prior B QW + + #stall + + extqh r20, r18, r0 # Get a piece of last B QW + + #stall + + or r27, r0, r27 # Combine + + xor r28, r27, r0 # Compare with A + + mskql r0, r19, r0 # Discard diffs after strings + + nop + +eql_u: cmpeq r0, 0, r0 # Return 1 or 0 as xor=0 or not + ret r31, (r26) + + +not_eq: clr r0 # Return false + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringCompareEqlSameLen diff --git a/private/crt32/misc/alpha/scmpeqlp.s b/private/crt32/misc/alpha/scmpeqlp.s new file mode 100644 index 000000000..85836d587 --- /dev/null +++ b/private/crt32/misc/alpha/scmpeqlp.s @@ -0,0 +1,443 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_eqlp(char *str1, long str1len, + # char *str2, long str2len, char pad); + # compares two strings of different lengths with padding. + # returns r0=1 if str1=str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r22 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 006 28 May 1992 WBN Initial version, replacing BLISS -005 + # + # 007 22 Sep 1992 KDG Add case-sensitive name + # + # 008 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # r20 = pad + # returns r0=1 if strings equal, r0=0 if not equal + # destroys r16-r22, r27-r28 + # + .globl _OtsStringCompareEqlPadded + .ent _OtsStringCompareEqlPadded +_OtsStringCompareEqlPadded: + .set noat + .set noreorder + .frame sp,0,r26 + + subq r17, r19, r21 # A length - B length + beq r17, a_empty # If A empty, go compare B with pad + + cmovgt r21, r19, r17 # R17 = min length + ldq_u r0, (r16) # Get first QW of A + + sll r20, 8, r28 # Start replicating pad + beq r19, b_empty # If B empty, go compare A with pad + + subq r17, 8, r17 # Is min length > 8? + ldq_u r19, (r18) # Get first QW of B + + or r20, r28, r20 # Pad in bytes 0,1 of R20 + bgt r17, big # Go handle strings > 8 bytes + + addq r18, r17, r18 # Point to end of B + addq r16, r17, r16 # Point to end of A + + extql r0, r16, r0 # Position start of string A + ldq_u r27, 7(r18) # Get end of string B + + extql r19, r18, r19 # Position start of string B + ldq_u r28, 7(r16) # Get end of string A + + subq r31, r17, r17 # R17 = 8 - length + extqh r27, r18, r27 # Position end of string B + + extqh r28, r16, r28 # Position end of string A + or r19, r27, r19 # Combine parts of B + + or r0, r28, r28 # Combine parts of A + xor r28, r19, r27 # Are they different? + + mskqh r27, r17, r27 # Clear off diffs preceding strings + sll r20, 16, r19 # Replicate pad while waiting + + clr r0 # Prepare to return false + beq r27, eq_so_far # Skip if entire min_length matched + + ret r31, (r26) # Strings differ, return false + + # Come here if min length > 8 + # + # r0 = first QW of A + # r16 -> A + # r17 = min length - 8 + # r18 -> B + # r19 = first QW of B + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # + #.odd +big: and r16, 7, r28 # A alignment, or amount not compared + + subq r18, r28, r18 # Back up B pointer that much + + addq r17, r28, r17 # (Len-8+align) is amount left to do + + and r18, 7, r22 # Is B now aligned? + ldq_u r27, 8(r18) # Get next QW of B + + subq r17, 16, r17 # More than 2 QW's left? + bne r22, unalign # Skip if B alignment doesn't match + + xor r0, r19, r22 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r22, r16, r22 # Discard junk preceding strings + ble r17, bottom # Skip if two quadwords or less to go + + # stall + +loop: bne r22, neq # Done if difference in prior compare + ldq_u r0, 16(r16) # Get yet another QW of A + + xor r28, r27, r22 # Compare prior QW's + ldq r19, 16(r18) # Get yet another QW of B + + subq r17, 16, r17 # Decrement length + bne r22, neq # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r0, r19, r22 # Compare QW's loaded at top of loop + bgt r17, loop # Repeat until two or less QWs left + +bottom: addq r17, 8, r19 # More than 1 QW left? + bne r22, neq # Done if difference in prior compare + + andnot r16, 7, r16 # Get actual A pointer + ble r19, last # Skip if this is last compare + + xor r28, r27, r22 # Compare QW's just loaded + ldq r27, 16(r18) # Get last QW of B + + bne r22, neq # Done if difference in this compare + ldq r28, 16(r16) # Get last QW of A + + mov r17, r19 + + nop + +last: xor r28, r27, r22 # Compare last QW's + beq r19, ck_last + + mskql r22, r19, r22 # Discard diffs after length + +ck_last: + bne r22, neq # See which is greater + + addq r17, 16, r17 # Get actual remaining length + sll r20, 16, r19 # Start shifting pad some more + + addq r16, r17, r16 # Point to end-8 of each string + addq r18, r17, r18 + + # Come here if strings match thru min_length + # + # r0 + # r16 -> A[min_length-8] (8 before first uncompared byte of A) + # r17 + # r18 -> B[min_length-8] (8 before first uncompared byte of B) + # r19 = pad in bytes 2,3 + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # +eq_so_far: + or r20, r19, r27 # Pad in bytes 0-3 + beq r21, equal # Strings same length, return equal + + sll r27, 32, r0 # Replicate pad some more + blt r21, b_longer # Go compare pad with B + + and r16, 7, r17 # Alignment of remaining A + ldq_u r28, 8(r16) # Get first data to compare with pad + + subq r21, 8, r21 # Length - 8 + or r27, r0, r27 # Pad in bytes 0-7 + + addq r21, r17, r21 # Remaining length after this QW + xor r28, r27, r22 # Compare A QW with pad + + mskqh r22, r16, r22 # Discard bytes preceding end of B + ble r21, a_last # Skip if this is last QW + + ldq_u r0, 16(r16) # Get QW 2 of A + subq r21, 16, r21 # Are there two more QW's? + + ble r21, a_bot # Skip loop if not +a_pad: bne r22, neq # Exit if diff in R28 + + ldq_u r28, 24(r16) # Get next QW of A + xor r0, r27, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq # Exit if diff in R0 + + ldq_u r0, 32(r16) # Get next QW of A + addq r16, 16, r16 # Update pointer + + xor r28, r27, r22 # Compare prior QW + bgt r21, a_pad # Repeat if more to compare + +a_bot: addq r21, 8, r21 # Another QW? + bne r22, neq # Exit if diff in R28 + + mov r0, r28 # Move this QW to common location + ble r21, a_skip # Skip if this is last QW + + ldq_u r28, 24(r16) # Next QW of A + xor r0, r27, r22 # Compare prior QW + + subq r21, 8, r21 + bne r22, neq # Exit if diff in R0 + +a_skip: xor r28, r27, r22 # Compare last QW +a_last: beq r21, a_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of string + nop + +a_end: cmpeq r22, 0, r0 # Return 1/0 for strings equal/not + ret r31, (r26) + + # Come here if A is nonempty, but B is empty. + # +b_empty: + subq r16, 8, r16 # Back up A pointer as expected + or r20, r28, r20 # Pad in bytes 0-1 + + sll r20, 16, r19 + br r31, eq_so_far # Go compare A with pad + + # Come here if A is empty (B might be empty too). + # + nop #.odd +a_empty: + sll r20, 8, r28 # Start replicating pad + + subq r18, 8, r18 # Back up B pointer as expected + beq r19, equal # Done if both strings empty + + or r20, r28, r20 # Pad in bytes 0-1 + sll r20, 16, r0 + + or r20, r0, r27 # Pad in bytes 0-3 + sll r27, 32, r0 + +b_longer: + and r18, 7, r17 # Alignment of remaining B + ldq_u r28, 8(r18) # Get first data to compare with pad + + addq r21, 8, r21 # - Length + 8 + or r27, r0, r0 # Pad in bytes 0-7 + + subq r17, r21, r21 # Remaining length after this QW + xor r0, r28, r22 # Compare B QW with pad + + mskqh r22, r18, r22 # Discard bytes preceding end of A + ble r21, b_last # Skip if last QW + + ldq_u r19, 16(r18) # Get QW 2 of B + subq r21, 16, r21 # Two more QW's? + + ble r21, b_bot # Skip if not +b_pad: bne r22, neq # Exit if diff in r28 + + ldq_u r28, 24(r18) # Get next QW of B + xor r0, r19, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq # Exit if diff in R19 + + ldq_u r19, 32(r18) # Get next QW of B + addq r18, 16, r18 # Update pointer + + xor r0, r28, r22 # Compare prior QW + bgt r21, b_pad # Repeat if more to compare + +b_bot: addq r21, 8, r21 # Another QW? + bne r22, neq # Exit if diff in R28 + + xor r0, r19, r22 # Check another QW + ble r21, b_last # Skip if that's the last one + + ldq_u r28, 24(r18) # Fetch another QW + bne r22, neq # Exit if diff in R19 + + subq r21, 8, r21 + nop + + xor r0, r28, r22 # Check that QW +b_last: beq r21, b_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of B + nop + +b_end: cmpeq r22, 0, r0 # Return 1/0 as strings equal/not + ret r31, (r26) + +equal: mov 1, r0 # Strings equal, return true + ret r31, (r26) + + #.align quad +unalign: + extql r19, r18, r19 # Get first part of B + + extqh r27, r18, r22 # Get second part of B + + #stall + + or r22, r19, r19 # Combine pieces of B + + xor r0, r19, r22 # Compare with A + + mskqh r22, r16, r22 # Trim junk preceding strings + blt r17, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r19, 16(r18) # Get more B + subq r17, 16, r17 # Decrement length + + bne r22, neq # Done if r0.ne.r19 + extql r27, r18, r0 # Get piece of B from prior QW + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r19, r18, r22 # Get piece of B from first QW in loop + + extql r19, r18, r19 # Get second piece of B from there + + or r0, r22, r22 # Combine pieces for first B + + ldq_u r0, 16(r16) # Get still more A + xor r28, r22, r22 # Compare with first A + + bne r22, neq # Done if r28.ne.r22 + extqh r27, r18, r22 # Start building second B + + addq r16, 16, r16 # Increment A pointer + + or r22, r19, r19 # Combine pieces for second B + + xor r0, r19, r22 # Compare with second A + bge r17, loop_u # Repeat if at least 16 more bytes + +bott_u: and r17, 8, r28 # At least 8 more bytes? + bne r22, neq # Done if r0.ne.r19 + + and r17, 7, r17 # How many odd bytes? + beq r28, last_u # Skip if not a whole QW + + extql r27, r18, r0 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r22 # Get a piece of new B QW + + # stall + + or r0, r22, r0 # Combine pieces + + xor r28, r0, r22 # Compare with A + + bne r22, neq # Done if r28.ne.r0 + +last_u: andnot r16, 7, r16 # What's the real address of A? + + sll r20, 16, r19 # Start replicating pad + beq r17, eq_so_far # Check padding if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + addq r18, r17, r0 # Point to end-8 of B + + ldq_u r0, 7(r0) # Get QW containing end of B + extql r27, r18, r27 # Get piece of prior B QW + + addq r16, r17, r16 # Point to end-8 of A + + extqh r0, r18, r22 # Get a piece of last B QW + + addq r18, r17, r18 # Point to end-8 of B + + or r27, r22, r27 # Combine + + xor r28, r27, r22 # Compare with A + + mskql r22, r17, r22 # Discard diffs after strings + + nop + + beq r22, eq_so_far # If still equal, go check pad + +neq: clr r0 # Return false + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringCompareEqlPadded diff --git a/private/crt32/misc/alpha/scmpleq.s b/private/crt32/misc/alpha/scmpleq.s new file mode 100644 index 000000000..6370ac284 --- /dev/null +++ b/private/crt32/misc/alpha/scmpleq.s @@ -0,0 +1,338 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_leqs(char *str1, long strlen, char *str2); + # compares two strings of the same length. + # returns r0=1 if str1<=str2, r0=0 otherwise. + # + # long ots_strcmp_leq(char *str1, long str1len, char *str2, long str2len); + # compares two strings of different lengths without padding. + # returns r0=1 if str1<=str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r21 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004 + # + # 006 29 Jan 1992 WBN Use .otsent macro + # + # 007 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 008 22 Sep 1992 KDG Add case-sensitive name + # + # 009 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # returns r0=1 if A less/equal, r0=0 if A greater + # destroys r16-r21, r27-r28 + # + .globl _OtsStringCompareLeq + .ent _OtsStringCompareLeq +_OtsStringCompareLeq: + .set noat + .set noreorder + .frame sp,0,r26 + + subq r17, r19, r21 # A_len - B_len + cmovgt r21, r19, r17 # r17 = min length + br r31, join + + # r16 --> A + # r17 = len + # r18 --> B + # returns r0=1 if A less/equal, r0=0 if A greater + # destroys r16-r21, r27-r28 + # + .globl _OtsStringCompareLeqSameLen + .aent _OtsStringCompareLeqSameLen +_OtsStringCompareLeqSameLen: + .frame sp,0,r26 + + clr r21 # Lengths are equal + +join: subq r17, 8, r19 # More than 8 bytes to compare? + beq r17, equal # Done if empty strings + + ldq_u r20, (r16) # Get first QW containing part of A + addq r18, r17, r27 # Point to end of B + + ldq_u r17, (r18) # Get first QW containing part of B + bgt r19, big # Skip if more than 8 bytes + + ldq_u r27, -1(r27) # Get last QW containing part of B + addq r16, r19, r28 # Point to end of A + + extql r20, r16, r20 # Get first part of A + + ldq_u r28, 7(r28) # Get last QW containing part of A + + extql r17, r18, r17 # Get first part of B + + extqh r27, r18, r27 # Get last part of B + + extqh r28, r16, r28 # Get last part of A + + or r17, r27, r27 # Combine B + + or r20, r28, r28 # Combine A + + xor r28, r27, r0 # Are they different? + + beq r19, ck_leq + mskql r0, r19, r0 # Discard differences after length + + #stall + +ck_leq: cmpbge r31, r0, r17 # Where is B = A? + beq r0, equal # (Skip if they're equal?) + + cmpbge r27, r28, r28 # Where is B >= A? + + addq r17, 1, r0 # Flip first difference + + andnot r28, r17, r28 # Where is B > A? + + and r28, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.odd +big: and r16, 7, r28 # A alignment, or amount not compared + + subq r18, r28, r18 # Back up B pointer that much + + and r18, 7, r0 # Is B now aligned? + + addq r19, r28, r19 # (Len-8+align) is amount left to do + ldq_u r27, 8(r18) # Get next QW of B + + subq r19, 16, r19 # More than 2 QW's left? + bne r0, unalign # Skip if B alignment doesn't match + + xor r20, r17, r0 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r0, r16, r0 # Discard junk preceding strings + ble r19, bottom # Skip if two quadwords or less to go + + # stall + +loop: bne r0, neq_2017 # Done if difference in prior compare + ldq_u r20, 16(r16) # Get yet another QW of A + + xor r28, r27, r0 # Compare prior QW's + ldq r17, 16(r18) # Get yet another QW of B + + subq r19, 16, r19 # Decrement length + bne r0, neq_2827 # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r20, r17, r0 # Compare QW's loaded at top of loop + bgt r19, loop # Repeat until two or less QWs left + +bottom: addq r19, 8, r19 # More than 1 QW left? + bne r0, neq_2017 # Done if difference in prior compare + + xor r28, r27, r0 # Compare QW's just loaded + ble r19, last # Skip if this is last compare + + bne r0, neq_2827 # Done if difference in this compare + ldq_u r28, 16(r16) # Get last QW of A + + ldq r27, 16(r18) # Get last QW of B + subq r19, 8, r19 + + #2 stalls + + xor r28, r27, r0 # Compare last QW's +last: beq r19, ck_last + + mskql r0, r19, r0 # Discard diffs after length + +ck_last: + bne r0, neq_2827 # See which is greater + +equal: cmple r21, r31, r0 # Equal: return A_len <= B_len + ret r31, (r26) + + #.align quad +unalign: + extql r17, r18, r17 # Get first part of B + + extqh r27, r18, r0 # Get second part of B + + #stall + + or r0, r17, r17 # Combine pieces of B + + xor r20, r17, r0 # Compare with A + + mskqh r0, r16, r0 # Trim junk preceding strings + blt r19, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r17, 16(r18) # Get more B + subq r19, 16, r19 # Decrement length + + bne r0, neq_20xx # Done if r20.ne.r17 + extql r27, r18, r20 # Get piece of B from prior QW + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r17, r18, r0 # Get piece of B from first QW in loop + + extql r17, r18, r17 # Get second piece of B from there + + or r20, r0, r0 # Combine pieces for first B + + ldq_u r20, 16(r16) # Get still more A + xor r28, r0, r0 # Compare with first A + + bne r0, neq_28xx # Done if r28.ne.r0 + extqh r27, r18, r0 # Start building second B + + addq r16, 16, r16 # Increment A pointer + + or r0, r17, r17 # Combine pieces for second B + + xor r20, r17, r0 # Compare with second A + bge r19, loop_u # Repeat if at least 16 more bytes + +bott_u: and r19, 8, r28 # At least 8 more bytes? + bne r0, neq_2017 # Done if r20.ne.r17 + + and r19, 7, r19 # How many odd bytes? + beq r28, last_u # Skip if not a whole QW + + extql r27, r18, r20 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r0 # Get a piece of new B QW + + #stall + + or r20, r0, r20 # Combine pieces + + xor r28, r20, r0 # Compare with A + + nop + bne r0, neq_28xx # Done if r28.ne.r20 + +last_u: addq r18, r19, r17 # Point to end of B + beq r19, eql_u # Check length diff if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + + ldq_u r20, 7(r17) # Get QW containing end of B + + extql r27, r18, r27 # Get piece of prior B QW + + #stall + + extqh r20, r18, r0 # Get a piece of last B QW + + #stall + + or r27, r0, r27 # Combine + + xor r28, r27, r0 # Compare with A + + mskql r0, r19, r0 # Discard diffs after strings + + #stall + + beq r0, eql_u # Done if they're still equal + + #.align quad +neq_28xx: + xor r28, r0, r27 # Recover B from A and xor +neq_2827: + cmpbge r31, r0, r17 # Where is B = A? + + cmpbge r27, r28, r20 # Where is B >= A? + + addq r17, 1, r0 # Flip first difference + + andnot r20, r17, r20 # Where is B > A? + + and r20, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.align quad +neq_20xx: + xor r20, r0, r17 # Recover B from A and xor +neq_2017: + cmpbge r31, r0, r27 # Where is B = A? + + cmpbge r17, r20, r20 # Where is B >= A? + + addq r27, 1, r0 # Flip first difference + + andnot r20, r27, r20 # Where is B > A? + + and r20, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + +eql_u: cmple r21, r31, r0 # Equal: return A_len <= B_len + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringCompareLeq diff --git a/private/crt32/misc/alpha/scmpleqp.s b/private/crt32/misc/alpha/scmpleqp.s new file mode 100644 index 000000000..b58fe2907 --- /dev/null +++ b/private/crt32/misc/alpha/scmpleqp.s @@ -0,0 +1,478 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_leqp(char *str1, long str1len, + # char *str2, long str2len, char pad); + # compares two strings of different lengths with padding. + # returns r0=1 if str1<=str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r22 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 006 28 May 1992 WBN Initial version, replacing BLISS -005 + # + # 007 22 Sep 1992 KDG Add case-sensitive name + # + # 008 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # r20 = pad + # returns r0=1 if A less/equal, r0=0 if A greater + # destroys r16-r22, r27-r28 + # + .globl _OtsStringCompareLeqPadded + .ent _OtsStringCompareLeqPadded +_OtsStringCompareLeqPadded: + .set noat + .set noreorder + .frame sp,0,r26 + + subq r17, r19, r21 # A length - B length + beq r17, a_empty # If A empty, go compare B with pad + + cmovgt r21, r19, r17 # R17 = min length + ldq_u r0, (r16) # Get first QW of A + + sll r20, 8, r28 # Start replicating pad + beq r19, b_empty # If B empty, go compare A with pad + + subq r17, 8, r17 # Is min length > 8? + ldq_u r19, (r18) # Get first QW of B + + or r20, r28, r20 # Pad in bytes 0,1 of R20 + bgt r17, big # Go handle strings > 8 bytes + + addq r18, r17, r18 # Point to end of B + addq r16, r17, r16 # Point to end of A + + extql r0, r16, r0 # Position start of string A + ldq_u r27, 7(r18) # Get end of string B + + extql r19, r18, r19 # Position start of string B + ldq_u r28, 7(r16) # Get end of string A + + subq r31, r17, r17 # R17 = 8 - length + extqh r27, r18, r27 # Position end of string B + + extqh r28, r16, r28 # Position end of string A + or r19, r27, r19 # Combine parts of B + + or r0, r28, r28 # Combine parts of A + xor r28, r19, r27 # Are they different? + + mskqh r27, r17, r27 # Clear off diffs preceding strings + sll r20, 16, r0 # Replicate pad while waiting + + cmpbge r31, r27, r17 # Make 1's where strings matched + beq r27, eq_so_far # Skip if entire min_length matched + + cmpbge r19, r28, r19 # Make 1's where B >= A + addq r17, 1, r0 # Flip first mismatch + + andnot r19, r17, r19 # 1's where A < B + and r19, r0, r0 # nonzero if A < B at first mismatch + + cmovne r0, 1, r0 # 1 if string A < string B + ret r31, (r26) + + # Come here if min length > 8 + # + # r0 = first QW of A + # r16 -> A + # r17 = min length - 8 + # r18 -> B + # r19 = first QW of B + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # + nop #.odd +big: and r16, 7, r28 # A alignment, or amount not compared + + subq r18, r28, r18 # Back up B pointer that much + + addq r17, r28, r17 # (Len-8+align) is amount left to do + + and r18, 7, r22 # Is B now aligned? + ldq_u r27, 8(r18) # Get next QW of B + + subq r17, 16, r17 # More than 2 QW's left? + bne r22, unalign # Skip if B alignment doesn't match + + xor r0, r19, r22 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r22, r16, r22 # Discard junk preceding strings + ble r17, bottom # Skip if two quadwords or less to go + + # stall + +loop: bne r22, neq_019 # Done if difference in prior compare + ldq_u r0, 16(r16) # Get yet another QW of A + + xor r28, r27, r22 # Compare prior QW's + ldq r19, 16(r18) # Get yet another QW of B + + subq r17, 16, r17 # Decrement length + bne r22, neq_2827 # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r0, r19, r22 # Compare QW's loaded at top of loop + bgt r17, loop # Repeat until two or less QWs left + +bottom: addq r17, 8, r19 # More than 1 QW left? + bne r22, neq_0xx # Done if difference in prior compare + + andnot r16, 7, r16 # Get actual A pointer + ble r19, last # Skip if this is last compare + + xor r28, r27, r22 # Compare QW's just loaded + ldq r27, 16(r18) # Get last QW of B + + bne r22, neq_28xx # Done if difference in this compare + ldq r28, 16(r16) # Get last QW of A + + mov r17, r19 + + nop + +last: xor r28, r27, r22 # Compare last QW's + beq r19, ck_last + + mskql r22, r19, r22 # Discard diffs after length + +ck_last: + bne r22, neq_2827 # See which is greater + + addq r17, 16, r17 # Get actual remaining length + sll r20, 16, r0 # Start shifting pad some more + + addq r16, r17, r16 # Point to end-8 of each string + addq r18, r17, r18 + + # Come here if strings match thru min_length + # + # r0 = pad in bytes 2,3 + # r16 -> A[min_length-8] (8 before first uncompared byte of A) + # r17 + # r18 -> B[min_length-8] (8 before first uncompared byte of B) + # r19 + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # +eq_so_far: + or r20, r0, r27 # Pad in bytes 0-3 + beq r21, equal # Strings same length, return equal + + sll r27, 32, r0 # Replicate pad some more + blt r21, b_longer # Go compare pad with B + + and r16, 7, r17 # Alignment of remaining A + ldq_u r28, 8(r16) # Get first data to compare with pad + + subq r21, 8, r21 # Length - 8 + or r27, r0, r27 # Pad in bytes 0-7 + + addq r21, r17, r21 # Remaining length after this QW + xor r28, r27, r22 # Compare A QW with pad + + mskqh r22, r16, r22 # Discard bytes preceding end of B + ble r21, a_last # Skip if this is last QW + + ldq_u r0, 16(r16) # Get QW 2 of A + subq r21, 16, r21 # Are there two more QW's? + + ble r21, a_bot # Skip loop if not +a_pad: bne r22, neq_2827 # Exit if diff in R28 + + ldq_u r28, 24(r16) # Get next QW of A + xor r0, r27, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq_0xx # Exit if diff in R0 + + ldq_u r0, 32(r16) # Get next QW of A + addq r16, 16, r16 # Update pointer + + xor r28, r27, r22 # Compare prior QW + bgt r21, a_pad # Repeat if more to compare + +a_bot: addq r21, 8, r21 # Another QW? + bne r22, neq_2827 # Exit if diff in R28 + + mov r0, r28 # Move this QW to common location + ble r21, a_skip # Skip if this is last QW + + ldq_u r28, 24(r16) # Next QW of A + xor r0, r27, r22 # Compare prior QW + + subq r21, 8, r21 + bne r22, neq_0xx # Exit if diff in R0 + +a_skip: xor r28, r27, r22 # Compare last QW +a_last: beq r21, a_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of string +a_end: bne r22, neq_2827 # Exit if diff in R28 + + mov 1, r0 # Strings equal, return true + ret r31, (r26) + + # Come here if A is nonempty, but B is empty. + # +b_empty: + subq r16, 8, r16 # Back up A pointer as expected + or r20, r28, r20 # Pad in bytes 0-1 + + sll r20, 16, r0 + br r31, eq_so_far # Go compare A with pad + + # Come here if A is empty (B might be empty too). + # + nop #.odd +a_empty: + sll r20, 8, r28 # Start replicating pad + + subq r18, 8, r18 # Back up B pointer as expected + beq r19, equal # Done if both strings empty + + or r20, r28, r20 # Pad in bytes 0-1 + sll r20, 16, r0 + + or r20, r0, r27 # Pad in bytes 0-3 + sll r27, 32, r0 + +b_longer: + and r18, 7, r17 # Alignment of remaining B + ldq_u r28, 8(r18) # Get first data to compare with pad + + addq r21, 8, r21 # - Length + 8 + or r27, r0, r0 # Pad in bytes 0-7 + + subq r17, r21, r21 # Remaining length after this QW + xor r0, r28, r22 # Compare B QW with pad + + mskqh r22, r18, r22 # Discard bytes preceding end of A + ble r21, b_last # Skip if last QW + + ldq_u r19, 16(r18) # Get QW 2 of B + subq r21, 16, r21 # Two more QW's? + + ble r21, b_bot # Skip if not +b_pad: bne r22, neq_0xx # Exit if diff in r28 + + ldq_u r28, 24(r18) # Get next QW of B + xor r0, r19, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq_019 # Exit if diff in R19 + + ldq_u r19, 32(r18) # Get next QW of B + addq r18, 16, r18 # Update pointer + + xor r0, r28, r22 # Compare prior QW + bgt r21, b_pad # Repeat if more to compare + +b_bot: addq r21, 8, r21 # Another QW? + bne r22, neq_0xx # Exit if diff in R28 + + xor r0, r19, r22 # Check another QW + ble r21, b_last # Skip if that's the last one + + ldq_u r28, 24(r18) # Fetch another QW + bne r22, neq_019 # Exit if diff in R19 + + subq r21, 8, r21 + nop + + xor r0, r28, r22 # Check that QW +b_last: beq r21, b_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of B +b_end: bne r22, neq_0xx # Exit if diff seen + +equal: mov 1, r0 # Strings equal, return true + ret r31, (r26) + + #.align quad +unalign: + extql r19, r18, r19 # Get first part of B + + extqh r27, r18, r22 # Get second part of B + + #stall + + or r22, r19, r19 # Combine pieces of B + + xor r0, r19, r22 # Compare with A + + mskqh r22, r16, r22 # Trim junk preceding strings + blt r17, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r19, 16(r18) # Get more B + subq r17, 16, r17 # Decrement length + + bne r22, neq_0xx # Done if r0.ne.r19 + extql r27, r18, r0 # Get piece of B from prior QW + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r19, r18, r22 # Get piece of B from first QW in loop + + extql r19, r18, r19 # Get second piece of B from there + + or r0, r22, r22 # Combine pieces for first B + + ldq_u r0, 16(r16) # Get still more A + xor r28, r22, r22 # Compare with first A + + bne r22, neq_28xx # Done if r28.ne.r22 + extqh r27, r18, r22 # Start building second B + + addq r16, 16, r16 # Increment A pointer + + or r22, r19, r19 # Combine pieces for second B + + xor r0, r19, r22 # Compare with second A + bge r17, loop_u # Repeat if at least 16 more bytes + +bott_u: and r17, 8, r28 # At least 8 more bytes? + bne r22, neq_019 # Done if r0.ne.r19 + + and r17, 7, r17 # How many odd bytes? + beq r28, last_u # Skip if not a whole QW + + extql r27, r18, r0 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r22 # Get a piece of new B QW + + # stall + + or r0, r22, r0 # Combine pieces + + xor r28, r0, r22 # Compare with A + + bne r22, neq_28xx # Done if r28.ne.r0 + +last_u: andnot r16, 7, r16 # What's the real address of A? + + sll r20, 16, r0 # Start replicating pad + beq r17, eq_so_far # Check padding if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + addq r18, r17, r19 # Point to end-8 of B + + ldq_u r19, 7(r19) # Get QW containing end of B + extql r27, r18, r27 # Get piece of prior B QW + + addq r16, r17, r16 # Point to end-8 of A + + extqh r19, r18, r22 # Get a piece of last B QW + + addq r18, r17, r18 # Point to end-8 of B + + or r27, r22, r27 # Combine + + xor r28, r27, r22 # Compare with A + + mskql r22, r17, r22 # Discard diffs after strings + + nop + + beq r22, eq_so_far # If still equal, go check pad + + #.align quad +neq_28xx: + xor r28, r22, r27 # Recover B from A and xor +neq_2827: + cmpbge r31, r22, r19 # Where is B = A? + + cmpbge r27, r28, r0 # Where is B >= A? + + addq r19, 1, r22 # Flip first difference + + andnot r0, r19, r0 # Where is B > A? + + and r0, r22, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.align quad +neq_0xx: + xor r0, r22, r19 # Recover B from A and xor +neq_019: + cmpbge r31, r22, r27 # Where is B = A? + + cmpbge r19, r0, r0 # Where is B >= A? + + addq r27, 1, r22 # Flip first difference + + andnot r0, r27, r0 # Where is B > A? + + and r0, r22, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringCompareLeqPadded diff --git a/private/crt32/misc/alpha/scmplss.s b/private/crt32/misc/alpha/scmplss.s new file mode 100644 index 000000000..ab043fb8f --- /dev/null +++ b/private/crt32/misc/alpha/scmplss.s @@ -0,0 +1,339 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_lsss(char *str1, long strlen, char *str2); + # compares two strings of the same length. + # returns r0=1 if str1<str2, r0=0 otherwise. + # + # long ots_strcmp_lss(char *str1, long str1len, char *str2, long str2len); + # compares two strings of different lengths without padding. + # returns r0=1 if str1<str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r21 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 005 27 Aug 1991 WBN Initial version, replacing BLISS -004 + # + # 006 29 Jan 1992 WBN Use .otsent macro + # + # 007 19 May 1992 KDG Changes for common VMS/OSF sources + # + # 008 22 Sep 1992 KDG Add case-sensitive name + # + # 009 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # returns r0=1 if A less, r0=0 if A greater/equal + # destroys r16-r21, r27-r28 + # + .globl _OtsStringCompareLss + .ent _OtsStringCompareLss +_OtsStringCompareLss: + .set noat + .set noreorder + .frame sp,0,r26 + + subq r17, r19, r21 # A_len - B_len + cmovgt r21, r19, r17 # r17 = min length + br r31, join + + # r16 --> A + # r17 = len + # r18 --> B + # returns r0=1 if A less, r0=0 if A greater/equal + # destroys r16-r21, r27-r28 + # + .globl _OtsStringCompareLssSameLen + .aent _OtsStringCompareLssSameLen +_OtsStringCompareLssSameLen: + .frame sp,0,r26 + + clr r21 # Lengths are equal + +join: subq r17, 8, r19 # More than 8 bytes to compare? + beq r17, equal # Done if empty strings + + ldq_u r20, (r16) # Get first QW containing part of A + addq r18, r17, r27 # Point to end of B + + ldq_u r17, (r18) # Get first QW containing part of B + bgt r19, big # Skip if more than 8 bytes + + ldq_u r27, -1(r27) # Get last QW containing part of B + addq r16, r19, r28 # Point to end of A + + extql r20, r16, r20 # Get first part of A + + ldq_u r28, 7(r28) # Get last QW containing part of A + + extql r17, r18, r17 # Get first part of B + + extqh r27, r18, r27 # Get last part of B + + extqh r28, r16, r28 # Get last part of A + + or r17, r27, r27 # Combine B + + or r20, r28, r28 # Combine A + + xor r28, r27, r0 # Are they different? + + beq r19, ck_leq + mskql r0, r19, r0 # Discard differences after length + + #stall + +ck_leq: cmpbge r31, r0, r17 # Where is B = A? + beq r0, equal # (Skip if they're equal?) + + cmpbge r27, r28, r28 # Where is B >= A? + + addq r17, 1, r0 # Flip first difference + + andnot r28, r17, r28 # Where is B > A? + + and r28, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.odd +big: and r16, 7, r28 # A alignment, or amount not compared + + subq r18, r28, r18 # Back up B pointer that much + + and r18, 7, r0 # Is B now aligned? + + addq r19, r28, r19 # (Len-8+align) is amount left to do + ldq_u r27, 8(r18) # Get next QW of B + + subq r19, 16, r19 # More than 2 QW's left? + bne r0, unalign # Skip if B alignment doesn't match + + xor r20, r17, r0 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r0, r16, r0 # Discard junk preceding strings + ble r19, bottom # Skip if two quadwords or less to go + + # stall + +loop: bne r0, neq_2017 # Done if difference in prior compare + ldq_u r20, 16(r16) # Get yet another QW of A + + xor r28, r27, r0 # Compare prior QW's + ldq r17, 16(r18) # Get yet another QW of B + + subq r19, 16, r19 # Decrement length + bne r0, neq_2827 # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r20, r17, r0 # Compare QW's loaded at top of loop + bgt r19, loop # Repeat until two or less QWs left + +bottom: addq r19, 8, r19 # More than 1 QW left? + bne r0, neq_2017 # Done if difference in prior compare + + xor r28, r27, r0 # Compare QW's just loaded + ble r19, last # Skip if this is last compare + + bne r0, neq_2827 # Done if difference in this compare + ldq_u r28, 16(r16) # Get last QW of A + + ldq r27, 16(r18) # Get last QW of B + subq r19, 8, r19 + + #2 stalls + + xor r28, r27, r0 # Compare last QW's +last: beq r19, ck_last + + mskql r0, r19, r0 # Discard diffs after length + +ck_last: + bne r0, neq_2827 # See which is greater + +equal: cmplt r21, r31, r0 # Equal: return A_len < B_len + ret r31, (r26) + + #.align quad +unalign: + extql r17, r18, r17 # Get first part of B + + extqh r27, r18, r0 # Get second part of B + + #stall + + or r0, r17, r17 # Combine pieces of B + + xor r20, r17, r0 # Compare with A + + mskqh r0, r16, r0 # Trim junk preceding strings + blt r19, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r17, 16(r18) # Get more B + subq r19, 16, r19 # Decrement length + + bne r0, neq_20xx # Done if r20.ne.r17 + extql r27, r18, r20 # Get piece of B from prior QW + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r17, r18, r0 # Get piece of B from first QW in loop + + extql r17, r18, r17 # Get second piece of B from there + + or r20, r0, r0 # Combine pieces for first B + + ldq_u r20, 16(r16) # Get still more A + xor r28, r0, r0 # Compare with first A + + bne r0, neq_28xx # Done if r28.ne.r0 + extqh r27, r18, r0 # Start building second B + + addq r16, 16, r16 # Increment A pointer + + or r0, r17, r17 # Combine pieces for second B + + xor r20, r17, r0 # Compare with second A + bge r19, loop_u # Repeat if at least 16 more bytes + +bott_u: and r19, 8, r28 # At least 8 more bytes? + bne r0, neq_2017 # Done if r20.ne.r17 + + and r19, 7, r19 # How many odd bytes? + beq r28, last_u # Skip if not a whole QW + + extql r27, r18, r20 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r0 # Get a piece of new B QW + + #stall + + or r20, r0, r20 # Combine pieces + + xor r28, r20, r0 # Compare with A + + nop + bne r0, neq_28xx # Done if r28.ne.r20 + +last_u: addq r18, r19, r17 # Point to end of B + beq r19, eql_u # Check length diff if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + + ldq_u r20, 7(r17) # Get QW containing end of B + + extql r27, r18, r27 # Get piece of prior B QW + + #stall + + extqh r20, r18, r0 # Get a piece of last B QW + + #stall + + or r27, r0, r27 # Combine + + xor r28, r27, r0 # Compare with A + + mskql r0, r19, r0 # Discard diffs after strings + + #stall + + beq r0, eql_u # Done if they're still equal + + #.align quad +neq_28xx: + xor r28, r0, r27 # Recover B from A and xor +neq_2827: + cmpbge r31, r0, r17 # Where is B = A? + + cmpbge r27, r28, r20 # Where is B >= A? + + addq r17, 1, r0 # Flip first difference + + andnot r20, r17, r20 # Where is B > A? + + and r20, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.align quad +neq_20xx: + xor r20, r0, r17 # Recover B from A and xor +neq_2017: + cmpbge r31, r0, r27 # Where is B = A? + + cmpbge r17, r20, r20 # Where is B >= A? + + addq r27, 1, r0 # Flip first difference + + andnot r20, r27, r20 # Where is B > A? + + and r20, r0, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + +eql_u: cmplt r21, r31, r0 # Equal: return A_len < B_len + ret r31, (r26) + + + .set at + .set reorder + .end _OtsStringCompareLss diff --git a/private/crt32/misc/alpha/scmplssp.s b/private/crt32/misc/alpha/scmplssp.s new file mode 100644 index 000000000..4243965d8 --- /dev/null +++ b/private/crt32/misc/alpha/scmplssp.s @@ -0,0 +1,478 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Bill Noyce + # + # + # long ots_strcmp_lssp(char *str1, long str1len, + # char *str2, long str2len, char pad); + # compares two strings of different lengths with padding. + # returns r0=1 if str1<str2, r0=0 otherwise. + # + # Special conventions: No stack space, r16-r22 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 006 28 May 1992 WBN Initial version, replacing BLISS -005 + # + # 007 22 Sep 1992 KDG Add case-sensitive name + # + # 008 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 --> A + # r17 = A_len + # r18 --> B + # r19 = B_len + # r20 = pad + # returns r0=1 if A less, r0=0 if A greater/equal + # destroys r16-r22, r27-r28 + # + .globl _OtsStringCompareLssPadded + .ent _OtsStringCompareLssPadded +_OtsStringCompareLssPadded: + .set noat + .set noreorder + .frame sp,0,r26 + + subq r17, r19, r21 # A length - B length + beq r17, a_empty # If A empty, go compare B with pad + + cmovgt r21, r19, r17 # R17 = min length + ldq_u r0, (r16) # Get first QW of A + + sll r20, 8, r28 # Start replicating pad + beq r19, b_empty # If B empty, go compare A with pad + + subq r17, 8, r17 # Is min length > 8? + ldq_u r19, (r18) # Get first QW of B + + or r20, r28, r20 # Pad in bytes 0,1 of R20 + bgt r17, big # Go handle strings > 8 bytes + + addq r18, r17, r18 # Point to end of B + addq r16, r17, r16 # Point to end of A + + extql r0, r16, r0 # Position start of string A + ldq_u r27, 7(r18) # Get end of string B + + extql r19, r18, r19 # Position start of string B + ldq_u r28, 7(r16) # Get end of string A + + subq r31, r17, r17 # R17 = 8 - length + extqh r27, r18, r27 # Position end of string B + + extqh r28, r16, r28 # Position end of string A + or r19, r27, r19 # Combine parts of B + + or r0, r28, r28 # Combine parts of A + xor r28, r19, r27 # Are they different? + + mskqh r27, r17, r27 # Clear off diffs preceding strings + sll r20, 16, r0 # Replicate pad while waiting + + cmpbge r31, r27, r17 # Make 1's where strings matched + beq r27, eq_so_far # Skip if entire min_length matched + + cmpbge r19, r28, r19 # Make 1's where B >= A + addq r17, 1, r0 # Flip first mismatch + + andnot r19, r17, r19 # 1's where A < B + and r19, r0, r0 # nonzero if A < B at first mismatch + + cmovne r0, 1, r0 # 1 if string A < string B + ret r31, (r26) + + # Come here if min length > 8 + # + # r0 = first QW of A + # r16 -> A + # r17 = min length - 8 + # r18 -> B + # r19 = first QW of B + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # + nop #.odd +big: and r16, 7, r28 # A alignment, or amount not compared + + subq r18, r28, r18 # Back up B pointer that much + + addq r17, r28, r17 # (Len-8+align) is amount left to do + + and r18, 7, r22 # Is B now aligned? + ldq_u r27, 8(r18) # Get next QW of B + + subq r17, 16, r17 # More than 2 QW's left? + bne r22, unalign # Skip if B alignment doesn't match + + xor r0, r19, r22 # Compare first (partial) QW + ldq_u r28, 8(r16) # Get next QW of A + + mskqh r22, r16, r22 # Discard junk preceding strings + ble r17, bottom # Skip if two quadwords or less to go + + # stall + +loop: bne r22, neq_019 # Done if difference in prior compare + ldq_u r0, 16(r16) # Get yet another QW of A + + xor r28, r27, r22 # Compare prior QW's + ldq r19, 16(r18) # Get yet another QW of B + + subq r17, 16, r17 # Decrement length + bne r22, neq_2827 # Done if difference in this compare + + ldq r27, 24(r18) # Get next QW of B + addq r18, 16, r18 # Increment pointer + + ldq_u r28, 24(r16) # Get next QW of A + addq r16, 16, r16 # Increment pointer + + xor r0, r19, r22 # Compare QW's loaded at top of loop + bgt r17, loop # Repeat until two or less QWs left + +bottom: addq r17, 8, r19 # More than 1 QW left? + bne r22, neq_0xx # Done if difference in prior compare + + andnot r16, 7, r16 # Get actual A pointer + ble r19, last # Skip if this is last compare + + xor r28, r27, r22 # Compare QW's just loaded + ldq r27, 16(r18) # Get last QW of B + + bne r22, neq_28xx # Done if difference in this compare + ldq r28, 16(r16) # Get last QW of A + + mov r17, r19 + + nop + +last: xor r28, r27, r22 # Compare last QW's + beq r19, ck_last + + mskql r22, r19, r22 # Discard diffs after length + +ck_last: + bne r22, neq_2827 # See which is greater + + addq r17, 16, r17 # Get actual remaining length + sll r20, 16, r0 # Start shifting pad some more + + addq r16, r17, r16 # Point to end-8 of each string + addq r18, r17, r18 + + # Come here if strings match thru min_length + # + # r0 = pad in bytes 2,3 + # r16 -> A[min_length-8] (8 before first uncompared byte of A) + # r17 + # r18 -> B[min_length-8] (8 before first uncompared byte of B) + # r19 + # r20 = pad in bytes 0,1 + # r21 = A length - B length + # r22 + # r27 + # r28 + # +eq_so_far: + or r20, r0, r27 # Pad in bytes 0-3 + beq r21, equal # Strings same length, return equal + + sll r27, 32, r0 # Replicate pad some more + blt r21, b_longer # Go compare pad with B + + and r16, 7, r17 # Alignment of remaining A + ldq_u r28, 8(r16) # Get first data to compare with pad + + subq r21, 8, r21 # Length - 8 + or r27, r0, r27 # Pad in bytes 0-7 + + addq r21, r17, r21 # Remaining length after this QW + xor r28, r27, r22 # Compare A QW with pad + + mskqh r22, r16, r22 # Discard bytes preceding end of B + ble r21, a_last # Skip if this is last QW + + ldq_u r0, 16(r16) # Get QW 2 of A + subq r21, 16, r21 # Are there two more QW's? + + ble r21, a_bot # Skip loop if not +a_pad: bne r22, neq_2827 # Exit if diff in R28 + + ldq_u r28, 24(r16) # Get next QW of A + xor r0, r27, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq_0xx # Exit if diff in R0 + + ldq_u r0, 32(r16) # Get next QW of A + addq r16, 16, r16 # Update pointer + + xor r28, r27, r22 # Compare prior QW + bgt r21, a_pad # Repeat if more to compare + +a_bot: addq r21, 8, r21 # Another QW? + bne r22, neq_2827 # Exit if diff in R28 + + mov r0, r28 # Move this QW to common location + ble r21, a_skip # Skip if this is last QW + + ldq_u r28, 24(r16) # Next QW of A + xor r0, r27, r22 # Compare prior QW + + subq r21, 8, r21 + bne r22, neq_0xx # Exit if diff in R0 + +a_skip: xor r28, r27, r22 # Compare last QW +a_last: beq r21, a_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of string +a_end: bne r22, neq_2827 # Exit if diff in R28 + + clr r0 # Strings equal, return false + ret r31, (r26) + + # Come here if A is nonempty, but B is empty. + # +b_empty: + subq r16, 8, r16 # Back up A pointer as expected + or r20, r28, r20 # Pad in bytes 0-1 + + sll r20, 16, r0 + br r31, eq_so_far # Go compare A with pad + + # Come here if A is empty (B might be empty too). + # + nop #.odd +a_empty: + sll r20, 8, r28 # Start replicating pad + + subq r18, 8, r18 # Back up B pointer as expected + beq r19, equal # Done if both strings empty + + or r20, r28, r20 # Pad in bytes 0-1 + sll r20, 16, r0 + + or r20, r0, r27 # Pad in bytes 0-3 + sll r27, 32, r0 + +b_longer: + and r18, 7, r17 # Alignment of remaining B + ldq_u r28, 8(r18) # Get first data to compare with pad + + addq r21, 8, r21 # - Length + 8 + or r27, r0, r0 # Pad in bytes 0-7 + + subq r17, r21, r21 # Remaining length after this QW + xor r0, r28, r22 # Compare B QW with pad + + mskqh r22, r18, r22 # Discard bytes preceding end of A + ble r21, b_last # Skip if last QW + + ldq_u r19, 16(r18) # Get QW 2 of B + subq r21, 16, r21 # Two more QW's? + + ble r21, b_bot # Skip if not +b_pad: bne r22, neq_0xx # Exit if diff in r28 + + ldq_u r28, 24(r18) # Get next QW of B + xor r0, r19, r22 # Check prior QW + + subq r21, 16, r21 # 2 more QW's? + bne r22, neq_019 # Exit if diff in R19 + + ldq_u r19, 32(r18) # Get next QW of B + addq r18, 16, r18 # Update pointer + + xor r0, r28, r22 # Compare prior QW + bgt r21, b_pad # Repeat if more to compare + +b_bot: addq r21, 8, r21 # Another QW? + bne r22, neq_0xx # Exit if diff in R28 + + xor r0, r19, r22 # Check another QW + ble r21, b_last # Skip if that's the last one + + ldq_u r28, 24(r18) # Fetch another QW + bne r22, neq_019 # Exit if diff in R19 + + subq r21, 8, r21 + nop + + xor r0, r28, r22 # Check that QW +b_last: beq r21, b_end # Can't use MSKQL if whole QW + + mskql r22, r21, r22 # Keep only up to end of B +b_end: bne r22, neq_0xx # Exit if diff seen + +equal: clr r0 # Strings equal, return false + ret r31, (r26) + + #.align quad +unalign: + extql r19, r18, r19 # Get first part of B + + extqh r27, r18, r22 # Get second part of B + + #stall + + or r22, r19, r19 # Combine pieces of B + + xor r0, r19, r22 # Compare with A + + mskqh r22, r16, r22 # Trim junk preceding strings + blt r17, bott_u # Skip if fewer than 16 bytes left + +loop_u: ldq_u r19, 16(r18) # Get more B + subq r17, 16, r17 # Decrement length + + bne r22, neq_0xx # Done if r0.ne.r19 + extql r27, r18, r0 # Get piece of B from prior QW + + ldq_u r27, 24(r18) # Get still more B + addq r18, 16, r18 # Increment B pointer + + ldq_u r28, 8(r16) # Get more A + extqh r19, r18, r22 # Get piece of B from first QW in loop + + extql r19, r18, r19 # Get second piece of B from there + + or r0, r22, r22 # Combine pieces for first B + + ldq_u r0, 16(r16) # Get still more A + xor r28, r22, r22 # Compare with first A + + bne r22, neq_28xx # Done if r28.ne.r22 + extqh r27, r18, r22 # Start building second B + + addq r16, 16, r16 # Increment A pointer + + or r22, r19, r19 # Combine pieces for second B + + xor r0, r19, r22 # Compare with second A + bge r17, loop_u # Repeat if at least 16 more bytes + +bott_u: and r17, 8, r28 # At least 8 more bytes? + bne r22, neq_019 # Done if r0.ne.r19 + + and r17, 7, r17 # How many odd bytes? + beq r28, last_u # Skip if not a whole QW + + extql r27, r18, r0 # Get a piece of B + ldq_u r27, 16(r18) # Load another QW of B + + addq r18, 8, r18 # Increment B pointer + ldq_u r28, 8(r16) # Load another QW of A + + addq r16, 8, r16 # Increment A pointer + + extqh r27, r18, r22 # Get a piece of new B QW + + # stall + + or r0, r22, r0 # Combine pieces + + xor r28, r0, r22 # Compare with A + + bne r22, neq_28xx # Done if r28.ne.r0 + +last_u: andnot r16, 7, r16 # What's the real address of A? + + sll r20, 16, r0 # Start replicating pad + beq r17, eq_so_far # Check padding if no more bytes + + ldq_u r28, 8(r16) # Get last QW of A + addq r18, r17, r19 # Point to end-8 of B + + ldq_u r19, 7(r19) # Get QW containing end of B + extql r27, r18, r27 # Get piece of prior B QW + + addq r16, r17, r16 # Point to end-8 of A + + extqh r19, r18, r22 # Get a piece of last B QW + + addq r18, r17, r18 # Point to end-8 of B + + or r27, r22, r27 # Combine + + xor r28, r27, r22 # Compare with A + + mskql r22, r17, r22 # Discard diffs after strings + + nop + + beq r22, eq_so_far # If still equal, go check pad + + #.align quad +neq_28xx: + xor r28, r22, r27 # Recover B from A and xor +neq_2827: + cmpbge r31, r22, r19 # Where is B = A? + + cmpbge r27, r28, r0 # Where is B >= A? + + addq r19, 1, r22 # Flip first difference + + andnot r0, r19, r0 # Where is B > A? + + and r0, r22, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + #.align quad +neq_0xx: + xor r0, r22, r19 # Recover B from A and xor +neq_019: + cmpbge r31, r22, r27 # Where is B = A? + + cmpbge r19, r0, r0 # Where is B >= A? + + addq r27, 1, r22 # Flip first difference + + andnot r0, r27, r0 # Where is B > A? + + and r0, r22, r0 # Keep only first difference + + cmovne r0, 1, r0 # Return 1 if A < B at first difference + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringCompareLssPadded diff --git a/private/crt32/misc/alpha/setjmp.s b/private/crt32/misc/alpha/setjmp.s new file mode 100644 index 000000000..65453c8be --- /dev/null +++ b/private/crt32/misc/alpha/setjmp.s @@ -0,0 +1,111 @@ +// TITLE("Set Jump") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// setjmp.s +// +// Abstract: +// +// This module implements the Alpha acc compiler specific routine to +// perform a setjmp. +// +// N.B. This module conditionally provides UNSAFE handling of setjmp and +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an uninitialized variable +// has been set to a nonzero value. +// +// Author: +// +// David N. Cutler (davec) 7-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Thomas Van Baak (tvb) 22-Apr-1993 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + +// +// Define variable that will cause setjmp/longjmp to be safe or unsafe with +// respect to structured exception handling. +// + + .globl _setjmpexused + .comm _setjmpexused, 4 + + SBTTL("Set Jump - acc version") +//++ +// +// int +// setjmp ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function saves the current nonvolatile register state in the +// specified jump buffer and returns a function value of zero. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + LEAF_ENTRY(setjmp) + + ldl v0, _setjmpexused // get value of switch variable + bne v0, 10f // if ne, provide safe setjmp + +// +// Provide unsafe handling of setjmp. +// + + stt f2, JbFltF2(a0) // save floating registers f2 - f9 + stt f3, JbFltF3(a0) // + stt f4, JbFltF4(a0) // + stt f5, JbFltF5(a0) // + stt f6, JbFltF6(a0) // + stt f7, JbFltF7(a0) // + stt f8, JbFltF8(a0) // + stt f9, JbFltF9(a0) // + + stq s0, JbIntS0(a0) // save integer registers s0 - s6/fp + stq s1, JbIntS1(a0) // + stq s2, JbIntS2(a0) // + stq s3, JbIntS3(a0) // + stq s4, JbIntS4(a0) // + stq s5, JbIntS5(a0) // + stq fp, JbIntS6(a0) // + + ldil t0, 1 // get unsafe setjmp flag + stl t0, JbType(a0) // set jump buffer context type + stq sp, JbIntSp(a0) // save stack pointer + stq ra, JbFir(a0) // get setjmp return address + + mov zero, v0 // set zero return value + ret zero, (ra) // return + +// +// Provide safe handling of setjmp. +// + +10: jmp zero, (v0) // finish in _setjmpex code + + .end setjmp diff --git a/private/crt32/misc/alpha/setjmpex.s b/private/crt32/misc/alpha/setjmpex.s new file mode 100644 index 000000000..3f39baa7b --- /dev/null +++ b/private/crt32/misc/alpha/setjmpex.s @@ -0,0 +1,147 @@ +// TITLE("Set Jump Extended") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// setjmpex.s +// +// Abstract: +// +// This module implements the Alpha acc compiler specific routine to +// provide SAFE handling of setjmp/longjmp with respect to structured +// exception handling. +// +// Author: +// +// David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Thomas Van Baak (tvb) 22-Apr-1993 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + +// +// Define variable that will cause setjmp/longjmp to be safe with respect +// to structured exception handling. +// + + .globl _setjmpexused + .data +_setjmpexused: + .long _setjmpex // set address of safe setjmp routine + + SBTTL("Set Jump Extended") +//++ +// +// int +// _setjmpex ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function implements a safe setjmp. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + .struct 0 +SjRa: .space 8 // saved return address +SjS0: .space 8 // saved integer register s0 +SjFl: .space 8 // InFunction flag variable +SjEf: .space 8 // EstablisherFrame(s) structure +SjCx: .space ContextFrameLength // context frame +SetjmpFrameLength: + + NESTED_ENTRY(_setjmpex, SetjmpFrameLength, zero) + + lda sp, -SetjmpFrameLength(sp) // allocate stack frame + stq ra, SjRa(sp) // save return address + stq s0, SjS0(sp) // save integer register s0 + + PROLOGUE_END + +// +// Save the nonvolatile machine state. +// + + lda t0, SjCx(sp) // address of context record + + stt f2, CxFltF2(t0) // save floating registers f2 - f9 + stt f3, CxFltF3(t0) // + stt f4, CxFltF4(t0) // + stt f5, CxFltF5(t0) // + stt f6, CxFltF6(t0) // + stt f7, CxFltF7(t0) // + stt f8, CxFltF8(t0) // + stt f9, CxFltF9(t0) // + + stq s0, CxIntS0(t0) // save integer registers s0 - fp/s6 + stq s1, CxIntS1(t0) // + stq s2, CxIntS2(t0) // + stq s3, CxIntS3(t0) // + stq s4, CxIntS4(t0) // + stq s5, CxIntS5(t0) // + stq fp, CxIntFp(t0) // + stq gp, CxIntGp(t0) // save integer register gp + + lda v0, SetjmpFrameLength(sp) // compute stack pointer address + stq v0, CxIntSp(t0) // save stack pointer + stq ra, CxIntRa(t0) // save return address + stq ra, CxFir(t0) // save continuation address + + ldil t1, 2 // get acc safe setjmp flag + stl t1, JbType(a0) // set jump buffer context type + stl ra, JbPc(a0) // save target instruction address + mov a0, s0 // preserve jump buffer address + +// +// Perform unwind to determine the virtual frame pointer of the caller. +// + + subl ra, 4, a0 // compute control PC address + bsr RtlLookupFunctionEntry // lookup function table address + + ldq a0, SjRa(sp) // get return address + subl a0, 4, a0 // compute control PC address + mov v0, a1 // set address of function entry + lda a2, SjCx(sp) // address of context record + lda a3, SjFl(sp) // set address of in function variable + lda a4, SjEf(sp) // set frame pointers address + mov zero, a5 // set context pointer array address + bsr RtlVirtualUnwind // compute virtual frame pointer value + +// +// Set return value, restore registers, deallocate stack frame, and return. +// + + ldl t0, SjEf(sp) // get virtual frame pointer + stl t0, JbFp(s0) // save virtual frame pointer address + mov zero, v0 // set return value + + ldq s0, SjS0(sp) // restore integer register s0 + ldq ra, SjRa(sp) // restore return address + lda sp, SetjmpFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end _setjmpex diff --git a/private/crt32/misc/alpha/sfill.s b/private/crt32/misc/alpha/sfill.s new file mode 100644 index 000000000..35814b321 --- /dev/null +++ b/private/crt32/misc/alpha/sfill.s @@ -0,0 +1,161 @@ + #++ + # Copyright 1991, 1994, Digital Equipment Corporation + # + # ots_fill(char *dstptr, long dstlen, unsigned char fill) + # + # Fill dstlen bytes of memory at *dstptr with "fill" + # + # Special conventions: No stack space, r16-r19 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # This is a GEM support routine for filling memory with a specified value, + # basically identical to the System V routine memset, with the 2nd two + # parameters reversed. This is optimized for extremely high performance + # both for small blocks (string padding) and large blocks (memory fill). + # In order to reduce overhead for small cases, they are retired as quickly + # as possible, more case analysis is reserved for cases which will do + # more. + # + # This version of OTS_FILL provides longword granularity for Alpha. + # + # 011 30 Aug 1994 WBN Longword granularity version based on + # OTS_FILL_ALPHA.M64 edit 010. + #-- + +#include "ots_defs.hs" + + # r16 = dst + # r17 = len + # r18 = fill byte + # destroys r16-r19, r27-r28 + + .globl _OtsFill + .ent _OtsFill +_OtsFill: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + + sll r18, 8, r19 # Start propagating byte to quadword + beq r17, done # No memory refs if len=0 + subq r17, 4, r28 # Length-4 + or r19, r18, r18 # Fill in bytes 0-1 + sll r18, 16, r19 + and r16, 3, r27 # Dst alignment (0-3) + or r19, r18, r18 # Fill in bytes 0-3 + andnot r16, 3, r16 # LW aligned dst pointer + addq r27, r28, r17 # Alignment + length - 4 + bge r28, geq4 # Lengths >= 4 may not need load + ldl r28, (r16) # Load first LW of dst + bgt r17, double # Skip if it crosses to next LW + addq r17, 4, r17 # Find endpoint within LW + xor r28, r18, r28 # Pre-flip all fill bits in dest + mskql r28, r27, r27 # Clear from startpoint thru 7 + mskqh r28, r17, r28 # Clear from 0 to endpoint + xor r27, r18, r27 # Combine fill with masked dest + xor r28, r27, r27 # Result is fill in center part only + stl r27, (r16) + ret r31, (r26) + +double: mskqh r18, r27, r19 # Discard fill preceding startpoint + mskql r28, r27, r28 # Clear from startpoint in first LW + ldl r27, 4(r16) # Load second LW of dst + mskql r18, r17, r18 # Discard fill following endpoint + or r28, r19, r28 # Insert fill in first LW + stl r28, (r16) + mskqh r27, r17, r27 # Clear up to endpoint in second LW + or r27, r18, r27 # Insert fill in second LW + stl r27, 4(r16) + ret r31, (r26) + + # Come here if length to be zeroed is >= 4. + # r16-> dst aligned to LW + # r17 = alignment + length - 4 + # r18 = fill in bytes 0-3 + # r27 = dst alignment within LW + # r28 = length-4 + + #.align quad + +geq4: and r16, 4, r28 # Which LW in QW to store first? + beq r17, simple # Go handle single aligned LW + sll r18, 32, r19 + bne r28, longs # Go use QW stores +quad: subq r17, 4, r17 # Does dest end in first QW? + or r18, r19, r18 # Fill in bytes 0-7 + blt r17, shortq # Ends within first QW + mskqh r18, r27, r28 # Clear initial bytes of fill + beq r27, wh_qw # Store a whole QW + ldq r19, (r16) # Load first QW of dest + mskql r19, r27, r19 # Clear from startpoint + or r19, r28, r28 # Combine first QW with fill +wh_qw: stq r28, (r16) # Store first QW of dest + br r31, join # Go fill rest of string + +simple: stl r18, (r16) # Single aligned LW + ret r31, (r26) + +shortq: ldq r28, (r16) # Load QW of dest + xor r28, r18, r28 # Pre-flip all fill bits in dest + mskql r28, r27, r27 # Clear from startpoint thru 7 + mskqh r28, r17, r28 # Clear from 0 up to endpoint + xor r27, r18, r27 # Combine fill with masked dest + xor r28, r27, r27 # Result is fill in center part only + stq r27, (r16) # Store + ret r31, (r26) + +longs: mskqh r18, r27, r28 # Clear initial bytes of LW fill + or r18, r19, r18 # Fill in bytes 0-7 + beq r27, wh_lw # Store a whole LW + ldl r19, (r16) # Load first LW of dest + mskql r19, r27, r19 # Clear from startpoint + or r19, r28, r28 # Combine first LW with fill +wh_lw: stl r28, (r16) # Store first LW of dest +join: subq r17, 32, r17 # At least 4 more quadwords? + and r17, 24, r27 # How many after multiple of 4? + bge r17, unroll # Taken branch for long strings +short: and r17, 7, r17 # How many odd bytes? + beq r27, last # Skip if no more whole QWs + stq_u r18, 8(r16) # Clear one... + subq r27, 16, r27 # Map 8/16/24 to -8/0/8 + addq r16, 8, r16 # Update dest pointer + blt r27, last # Skip if no more whole QWs + #stall + stq_u r18, 8(r16) # Clear two... + addq r16, 8, r16 # Update dest pointer + nop + beq r27, last # Skip if no more whole QWs + stq_u r18, 8(r16) # Clear three... + addq r16, 8, r16 # Update dest pointer +last: beq r17, done # Finished if no odd bytes + ldq_u r27, 8(r16) # Load last QW of dest + subq r17, 4, r28 # More than a LW left? + andnot r16, 7, r16 # Clean pointer for STL + mskql r18, r17, r18 # Discard unneeded fill bytes + #stall + mskqh r27, r17, r27 # Clear up to endpoint in last QW + #stall + or r27, r18, r27 # Combine fill with last QW + bgt r28, lastq # Go store a QW + stl r27, 8(r16) # LW store for last piece +done: ret r31, (r26) + +lastq: stq r27, 8(r16) # QW store for last piece + ret r31, (r26) + + +unroll: stq_u r18, 8(r16) # Store 4 QWs per iteration + stq_u r18, 16(r16) + stq_u r18, 24(r16) + subq r17, 32, r17 # Decrement remaining count + stq_u r18, 32(r16) + addq r16, 32, r16 # Update dest pointer + bge r17, unroll # repeat until done + br r31, short # Then handle leftovers + + .set at + .set reorder + .end _OtsFill diff --git a/private/crt32/misc/alpha/sloc.s b/private/crt32/misc/alpha/sloc.s new file mode 100644 index 000000000..30fda8c6e --- /dev/null +++ b/private/crt32/misc/alpha/sloc.s @@ -0,0 +1,702 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # This module provides support for string index, search, and verify. + # + # Authors: + # + # Bill Noyce + # Kent Glossop + # + # long ots_index(const char *str, long strlen, const char *pat, long patlen); + # + # Searches a string for a substring + # returns r0=zero-based position if found, or -1 if not. + # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra) + # + # long ots_search(const char *str, long strlen, const char *cset, long csetlen); + # + # Searches a string for any character in a set of characters + # returns r0=zero-based position if found, or -1 if not. + # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra) + # + # long ots_search_char(const char *str, long strlen, char pat); + # (also known as ots_index_char) + # + # Searches a string for a signle pattern character + # returns r0=zero-based position if found, or -1 if not. + # Register usage: r0, r16-r18 and r27-r28 ONLY (r26 is ra) + # (Note: GEM presumes r19 is also killed) + # + # long ots_search_mask(const char *str, long strlen, const char maskvec[], int mask) + # + # Searches a string until a character matching at least one bit + # in a mask is found in a table (similar to a VAX SCANC instruction.) + # returns r0=zero-based position if found, or -1 if not. + # Register usage: r0-1, r16-r21 and r27-r28 ONLY (r26 is ra) + # + # long ots_verify(char *str, long strlen, char *cset, long csetlen); + # + # Verifies a string against a set of characters + # returns r0=zero-based position for mismatch, or -1 if all validate. + # Register usage: r0-r1, r16-r23 and r27-r28 ONLY (r26 is ra) + # + # long ots_verify_char(char *str, long strlen, char pat); + # + # Verifies a string against a single character + # returns r0=zero-based position for mismatch, or -1 if not. + # Register usage: r0, r16-r18 and r27-r28 ONLY (r26 is ra) + # (Note: GEM presumes r19 is also killed) + # + # long ots_verify_mask(const char *str, long strlen, const char maskvec[], int mask) + # + # Verifies a string until a character not matching at least one bit + # in a mask is found in a table (similar to a VAX SPANC instruction.) + # returns r0=zero-based position if found, or -1 if not. + # Register usage: r0-1, r16-r21 and r27-r28 ONLY (r26 is ra) + # + # Special conventions for all: + # No stack space + # No linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 006 28 May 1992 WBN Initial version, replacing BLISS -005 + # + # 007 22 Sep 1992 KDG Add case-sensitive names + # + # 008 14 Nov 1992 KDG - Merge modules together (allows index/search/verify + # to use the single-character versions w/o calls) + # - initial multi-character index/search/verify + # + # 009 4 Dec 1992 KDG Fix bgt that should have been bge (GEM_BUGS #2091) + # + # 010 26 Jan 1993 KDG Add underscore + # + # All of the routines other than the single character search/verify could + # be significantly improved at some point in the future + #-- + +#include "ots_defs.hs" + + # "Package" + # + .globl _OtsLocation + .ent _OtsLocation +_OtsLocation: + .set noat + .set noreorder + + # ots_index + # This is currently a primitive brute-force string index (only marginally + # better than the original compiled code. Should be tailored to compare + # up to 8 at a time, particularly for patterns <= 8 characters.) + + # register use + # r0 - remaining match positions counter (-1) + # r1 - loop counter [rlen] + # r16 - source pointer (incremented on each match) + # r17 - source length + # r18 - pattern pointer + # r19 - pattern length + # r20 - loop source pointer [rsp] + # r21 - loop source temp [rs] + # r22 - loop pattern pointer [rpp] + # r23 - loop pattern temp [rp] + # r27 - available + # r28 - available + + .globl _OtsStringIndex + .aent _OtsStringIndex +_OtsStringIndex: + .frame sp,0,r26 + + cmpeq r19, 1, r20 # check for single-character index + beq r19, i_ret0 # pattern length 0 always matches @0 + subq r17, r19, r0 # number of match positions - 1 + bne r20, search_single # single character index + blt r0, i_retm1 # return -1 if no match positions + + # outer loop +i_outlp: + lda r20, -1(r16) # initialize source pointer + lda r22, -1(r18) # initialize pattern pointer + mov r19, r1 # initialize length counter + + # core brute-force matching loop +i_matlp: + ldq_u r21, 1(r20) # load qw containing source byte + lda r20, 1(r20) # bump source pointer + ldq_u r23, 1(r22) # load qw containing pattern byte + lda r22, 1(r22) # bump pattern pointer + subq r1, 1, r1 # decrement length + extbl r21, r20, r21 # extract source byte + extbl r23, r22, r23 # extract pattern byte + xor r21, r23, r21 # match? + bne r21, i_mismat # if not, try pattern at next position + bgt r1, i_matlp # continue matching pattern at current position? + + # matched +i_ret: + subq r17, r19, r1 # number of match positions - 1 + subq r1, r0, r0 # actual position + ret r31, (r26) + + # mismatch at current position - advance to next if more positions +i_mismat: + subq r0, 1, r0 # decrement match positions + lda r16, 1(r16) # set r16 to next match position + bge r0, i_outlp # if remaining positions, attempt match + +i_retm1: + lda r0, -1(r31) # return -1 + ret r31, (r26) + +i_ret0: clr r0 + ret r31, (r26) + + # ots_search + # R16 -> string + # R17 = length + # R18 -> character set + # R19 = character set length + # result in R0: -1 if all matched, or position in range 0..length-1 + # destroys R0-R1, R16-R23, R27-R28 + # + # This routine could definitely be improved. (It should only + # be necessary to go to memory for every 8th character for both + # the string and the character set, and for character sets + # <= 8 characters, it should be possible to simply keep the + # set in a register while the string is being processed.) + # + .globl _OtsStringSearch + .aent _OtsStringSearch +_OtsStringSearch: + .frame sp,0,r26 + + cmpeq r19, 1, r0 # check for single-character search, clear r0 otherwise + ble r19, s_retm1 # return -1 if no characters in the match set + bne r0, search_single # single character search + nop + + # outer loop +s_outlp: + ldq_u r20, (r16) # load qw containing source byte + lda r22, -1(r18) # initialize character set pointer + mov r19, r1 # initialize character set length counter + extbl r20, r16, r20 # extract the source byte to match + + # core brute-force matching loop +s_matlp: + ldq_u r23, 1(r22) # load qw containing character set byte + lda r22, 1(r22) # bump character set pointer + subq r1, 1, r1 # decrement remaining cset length + extbl r23, r22, r23 # extract character set byte + xor r20, r23, r21 # match? + beq r21, s_match # if match, we're done + bgt r1, s_matlp # continue matching pattern at current position? + + # no current position - advance to next if more positions + lda r16, 1(r16) # bump source pointer + addq r0, 1, r0 # increment position + subq r17, 1, r17 # decrement match count + bgt r17, s_outlp # if remaining positions, attempt match +s_retm1:lda r0, -1(r31) # if not, return -1 +s_match:ret r31, (r26) + +search_single: + ldq_u r19, (r18) # load the quadword containing the byte + extbl r19, r18, r18 # extract the byte of interest + # and fall through to the character search rtn + + # ots_search_char (ots_index_char) + # r16 -> string + # r17 = length + # r18 = character to find + # result in r0: -1 if not found, or position in range 0..length-1 + # destroys r16-r18, r27-r28 + # + .globl _OtsStringSearchChar + .aent _OtsStringSearchChar +_OtsStringSearchChar: + .globl _OtsStringIndexChar + .aent _OtsStringIndexChar +_OtsStringIndexChar: + .frame sp,0,r26 +search_char: + sll r18, 8, r28 # Replicate char in the quadword... + beq r17, sc_fail # Quick exit if length=0 + + ldq_u r27, (r16) # First quadword of string + addq r16, r17, r0 # Point to end of string + + subq r17, 8, r17 # Length > 8? + or r18, r28, r18 # ... + + sll r18, 16, r28 # ... + bgt r17, sc_long # Skip if length > 8 + + ldq_u r16, -1(r0) # Last quadword of string + extql r27, r0, r27 # Position string at high end of QW + + or r18, r28, r18 # ... + sll r18, 32, r28 # ... + + extqh r16, r0, r16 # Position string at high end of QW + or r18, r28, r18 # Pattern fills a quadword + + or r27, r16, r27 # String fills a quadword + xor r27, r18, r27 # Diff betw. string and pattern + + cmpbge r31, r27, r27 # Set 1's where string=pattern + subq r31, r17, r17 # Compute 8 - length + + srl r27, r17, r27 # Shift off bits not part of string + clr r0 # Set return value + + and r27, 0xF, r28 # One of first 4 characters? + blbs r27, sc_done # Return 0 if first char matched + + subq r27, 1, r0 # Flip the first '1' bit + beq r28, sc_geq_4 # Skip if no match in first 4 + + andnot r27, r0, r0 # Make one-bit mask of first match + srl r0, 2, r0 # Map 2/4/8 -> 0/1/2 + + # stall + + addq r0, 1, r0 # Bump by 1 + ret r31, (r26) # return + +sc_geq_4: + andnot r27, r0, r28 # Make one-bit mask of first match + beq r27, sc_done # Return -1 if there were none + + srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4 + srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1 + + addq r27, 4, r0 # Bump by 4 + subq r0, r28, r0 # and correct + +sc_done:ret r31, (r26) + + # Enter here if string length > 8. + # R16 -> start of string + # R17 = length - 8 + # R18 = fill in bytes 0,1 + # R27 = 1st QW of string + # R28 = fill in bytes 2,3 + + #.odd +sc_long:or r18, r28, r18 # R18 has pattern in low 4 bytes + + sll r18, 32, r28 # ... + and r16, 7, r0 # Where in QW did we start? + + or r18, r28, r18 # Pattern fills a QW + ldq_u r28, 8(r16) # Get next QW (string B) + + xor r27, r18, r27 # Diff Betw. string and pattern + cmpbge r31, r27, r27 # Set 1's where string=pattern + + addq r17, r0, r17 # Remaining length after 1st QW + srl r27, r0, r27 # Discard bits preceding string + + subq r17, 16, r17 # More than two QW's to go? + sll r27, r0, r27 # Reposition like other bits + + subq r17, r0, r0 # Remember start point to compute len + ble r17, sc_bottom # Skip the loop if 2 QW's or less + +sc_loop:xor r28, r18, r28 # Diff betw string B and pattern + bne r27, sc_done_a # Exit if a match in string A + + cmpbge r31, r28, r28 # 1's where string B = pattern + ldq_u r27, 16(r16) # Load string A + + subq r17, 16, r17 # Decrement remaining length + bne r28, sc_done_b # Exit if a match in string B + + ldq_u r28, 24(r16) # Load string B + addq r16, 16, r16 # Increment pointer + + xor r27, r18, r27 # Diff betw string A and pattern + cmpbge r31, r27, r27 # 1's where string A = pattern + + bgt r17, sc_loop # Repeat if more than 2 QW's left + + nop #.align quad + +sc_bottom: + bne r27, sc_done_a # Exit if a match in string A + addq r17, 8, r27 # More than 1 QW left? + + xor r28, r18, r28 # Diff betw string B and pattern + ble r27, sc_last # Skip if this is last QW + + cmpbge r31, r28, r27 # 1's where string B = pattern + ldq_u r28, 16(r16) # Load string A + + subq r17, 8, r17 # Adjust len for final return + bne r27, sc_done_a # Exit if a match in string B + + addq r17, 8, r27 # Ensure -7 <= (r27=len-8) <= 0 + xor r28, r18, r28 # Diff betw string A and pattern + +sc_last:mskqh r27, r27, r27 # Nonzero in bytes beyond string + subq r17, 8, r17 # Adjust len for final return + + or r28, r27, r28 # Zeros only for matches within string + cmpbge r31, r28, r27 # Where are the matches? + + bne r27, sc_done_a # Compute index if a match found +sc_fail:lda r0, -1(r31) # Else return -1 + + ret r31, (r26) + + nop #.align 8 + +sc_done_b: + addq r17, 8, r17 # Adjust length + mov r28, r27 # Put mask where it's expected + +sc_done_a: + subq r0, r17, r0 # (start - remaining) = base index + blbs r27, sc_exit # Return R0 if first char matched + + and r27, 0xF, r16 # One of first 4 characters? + subq r27, 1, r28 # Flip the first '1' bit + + andnot r27, r28, r28 # Make one-bit mask of first match + beq r16, sc_geq_4x # Skip if no match in first 4 + + srl r28, 2, r28 # Map 2/4/8 -> 0/1/2 + addq r0, 1, r0 # Bump by 1 + + addq r0, r28, r0 # Add byte offset +sc_exit:ret r31, (r26) # return + +sc_geq_4x: + addq r0, 4, r0 # Bump by 4 + srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4 + + srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1 + addq r0, r27, r0 # Add 0/1/2/4 + + subq r0, r28, r0 # and correct + ret r31, (r26) + + # ots_search_mask + # This routine could be tailored by loading a longword or + # a quadword at a time and doing table lookups on the + # characters largely in parallel. + # + .globl _OtsStringSearchMask + .aent _OtsStringSearchMask +_OtsStringSearchMask: + .frame sp,0,r26 + + lda r16, -1(r16) # bias initial address for better loop code + nop # should be lnop (unop) or fnop to dual issue + lda r0, -1(r31) # initialize position to -1 + ble r17, sm_ret # return -1 if source len is zero + # slow way - ~14 cycles/byte +sm_loop: + ldq_u r21, 1(r16) # load qw containing the byte + lda r16, 1(r16) # bump pointer + addq r0, 1, r0 # bump position + subq r17, 1, r17 # decrement the length + extbl r21, r16, r21 # extract the byte + addq r21, r18, r21 # get the byte in the table + ldq_u r20, (r21) # load qw from table containing lookup + extbl r20, r21, r20 # extract table byte + and r20, r19, r20 # check if any bits in the mask match + beq r17, sm_end # if last character, handle specially + beq r20, sm_loop # if no match, go do the loop again +sm_ret: + ret r31, (r26) # if not a match, we're done +sm_end: lda r21, -1(r31) # get -1 + cmoveq r20, r21, r0 # -1 if last char didn't match + ret r31, (r26) + + # ots_verify + # R16 -> string + # R17 = length + # R18 -> character set + # R19 = character set length + # result in R0: -1 if all matched, or position in range 0..length-1 + # destroys R0-R1, R16-R23, R27-R28 + # + # This routine could definitely be improved. (It should only + # be necessary to go to memory for every 8th character for both + # the string and the character set, and for character sets + # <= 8 characters, it should be possible to simply keep the + # set in a register while the string is being processed.) + # + .globl _OtsStringVerify + .aent _OtsStringVerify +_OtsStringVerify: + .frame sp,0,r26 + + cmpeq r19, 1, r0 # check for single-character search, clear r0 otherwise + ble r19, v_ret0 # return 0 if no characters in the match set + bne r0, verify_single # single character verify + nop + # outer loop +v_outlp: + ldq_u r20, (r16) # load qw containing source byte + lda r22, -1(r18) # initialize character set pointer + mov r19, r1 # initialize character set length counter + extbl r20, r16, r20 # extract the source byte to match + + # core brute-force matching loop +v_matlp: + ldq_u r23, 1(r22) # load qw containing character set byte + lda r22, 1(r22) # bump character set pointer + subq r1, 1, r1 # decrement remaining cset length + extbl r23, r22, r23 # extract character set byte + xor r20, r23, r21 # match? + beq r21, v_match # if match, move to the next character + bgt r1, v_matlp # continue matching pattern at current position? + # if we made it through the whole character set, this is a mismatch +v_ret0: ret r31, (r26) +v_match: # match at current position - advance to next if more positions + lda r16, 1(r16) # bump source pointer + addq r0, 1, r0 # increment position + subq r17, 1, r17 # decrement match count + bgt r17, v_outlp # if remaining positions, attempt match + lda r0, -1(r31) # if everything verified, return -1 + ret r31, (r26) + +verify_single: + ldq_u r19, (r18) # load the quadword containing the byte + extbl r19, r18, r18 # extract the byte of interest + # and fall through to the character verify rtn + + # ots_verify_char + # R16 -> string + # R17 = length + # R18 = character to check + # result in R0: -1 if all matched, or position in range 0..length-1 + # destroys R16-R18, R27-R28 + # + .globl _OtsStringVerifyChar + .aent _OtsStringVerifyChar +_OtsStringVerifyChar: + .frame sp,0,r26 + + sll r18, 8, r28 # Replicate char in the quadword... + beq r17, vc_fail # Quick exit if length=0 + + ldq_u r27, (r16) # First quadword of string + addq r16, r17, r0 # Point to end of string + + subq r17, 8, r17 # Length > 8? + or r18, r28, r18 # ... + + sll r18, 16, r28 # ... + bgt r17, vc_long # Skip if length > 8 + + ldq_u r16, -1(r0) # Last quadword of string + extql r27, r0, r27 # Position string at high end of QW + + or r18, r28, r18 # ... + sll r18, 32, r28 # ... + + extqh r16, r0, r16 # Position string at high end of QW + or r18, r28, r18 # Pattern fills a quadword + + or r27, r16, r27 # String fills a quadword + xor r27, r18, r18 # Diff betw. string and pattern + + subq r31, r17, r17 # 8 - length + extql r18, r17, r28 # Shift off bytes preceding string + + lda r0, -1(r31) # Prepare to return -1 for all matched + cmpbge r31, r28, r27 # Set 1's where string=pattern + + addl r28, 0, r18 # Is first LW all zero? + beq r28, vc_done # Quick exit if all matched + + addq r27, 1, r28 # Flip the first '0' bit + beq r18, vc_geq_4 # No diffs in first longword + + andnot r28, r27, r28 # Make one-bit mask of first diff + srl r28, 2, r0 # Map 1/2/4/8 -> 0/0/1/2 + + and r27, 1, r27 # 1 if first character matched + addq r0, r27, r0 # Bump by 1 if so + + ret r31, (r26) # return + + nop #.align 8 + +vc_geq_4: + andnot r28, r27, r28 # Make one-bit mask of first diff + srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4 + + srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1 + addq r27, 4, r0 # Bump by 4 + + subq r0, r28, r0 # and correct 4/5/6/8 -> 4/5/6/7 +vc_done:ret r31, (r26) + + # Enter here if string length > 8. + # R16 -> start of string + # R17 = length - 8 + # R18 = fill in bytes 0,1 + # R27 = 1st QW of string + # R28 = fill in bytes 2,3 + + #.align 8 +vc_long:and r16, 7, r0 # Where in QW did we start? + or r18, r28, r18 # R18 has pattern in low 4 bytes + + sll r18, 32, r28 # ... + addq r17, r0, r17 # Remaining length after 1st QW + + or r18, r28, r18 # Pattern fills a QW + ldq_u r28, 8(r16) # Get next QW (string B) + + xor r27, r18, r27 # Diff Betw. string and pattern + mskqh r27, r0, r27 # Discard diffs before string + + subq r17, 16, r17 # More than two QW's to go? + subq r17, r0, r0 # Remember start point to compute len + + ble r17, vc_bottom # Skip the loop if 2 QW's or less +vc_loop:bne r27, vc_done_a + + ldq_u r27, 16(r16) # Load string A + xor r28, r18, r28 # Diff betw string B and pattern + + subq r17, 16, r17 # Decrement remaining length + bne r28, vc_done_b # Exit if a diff in string B + + ldq_u r28, 24(r16) # Load string B + addq r16, 16, r16 # Increment pointer + + xor r27, r18, r27 # Diff betw string A and pattern + bgt r17, vc_loop # Repeat if more than 2 QW's left + +vc_bottom: + bne r27, vc_done_a # Exit if a match in string A + addq r17, 8, r17 # More than 1 QW left? + + xor r28, r18, r27 # Diff betw string B and pattern + ble r17, vc_last # Skip if this is last QW + + subq r17, 16, r17 # Adjust len for final return + bne r27, vc_done_a # Exit if a match in string B + + ldq_u r28, 16(r16) # Load string A + addq r17, 8, r17 # Ensure -7 <- (r17=len-8) <= 0 + + nop + xor r28, r18, r27 # Diff betw string A and pattern + +vc_last:mskqh r17, r17, r28 # -1 in bytes beyond string + subq r17, 16, r17 # Adjust len for final return + + andnot r27, r28, r27 # Nonzeros only for diffs within string + bne r27, vc_done_a # Compute index if a diff found + +vc_fail:lda r0, -1(r31) # Else return -1 + ret r31, (r26) + +vc_done_b: + addq r17, 8, r17 # Adjust length + mov r28, r27 # Put difference where it's expected + +vc_done_a: + cmpbge r31, r27, r28 # 1's where they match + subq r0, r17, r0 # (start - remaining) = base index + + addl r27, 0, r16 # First longword all zero? + blbc r28, vc_exit # Return R0 if first char different + + addq r28, 1, r27 # Flip the first '0' bit + beq r16, vc_geq_4x # Skip if no match in first 4 + + andnot r27, r28, r28 # Make one-bit mask of first match + srl r28, 2, r28 # Map 2/4/8 -> 0/1/2 + + addq r0, 1, r0 # Bump by 1 + addq r0, r28, r0 # Add byte offset + +vc_exit:ret r31, (r26) # return + +vc_geq_4x: + andnot r27, r28, r28 # Make one-bit mask of first match + + srl r28, 5, r27 # Map 10/20/48/80 -> 0/1/2/4 + addq r0, 4, r0 # Bump by 4 + + srl r28, 7, r28 # Map 10/20/40/80 -> 0/0/0/1 + addq r0, r27, r0 # Add 0/1/2/4 + + subq r0, r28, r0 # and correct + ret r31, (r26) + + # ots_verify_mask + # This routine could be tailored by loading a longword or + # a quadword at a time and doing table lookups on the + # characters largely in parallel. + # + .globl _OtsStringVerifyMask + .aent _OtsStringVerifyMask +_OtsStringVerifyMask: + .frame sp,0,r26 + + lda r16, -1(r16) # bias initial address for better loop code + nop # should be lnop (unop) or fnop to dual issue + lda r0, -1(r31) # initialize position to -1 + ble r17, vm_ret # return -1 if source len is zero + # slow way - ~14 cycles/byte +vm_loop: + ldq_u r21, 1(r16) # load qw containing the byte + lda r16, 1(r16) # bump pointer + addq r0, 1, r0 # bump position + subq r17, 1, r17 # decrement the length + extbl r21, r16, r21 # extract the byte + addq r21, r18, r21 # get the byte in the table + ldq_u r20, (r21) # load qw from table containing lookup + extbl r20, r21, r20 # extract table byte + and r20, r19, r20 # check if any bits in the mask match + beq r17, vm_end # if last character, handle specially + bne r20, vm_loop # if match, go do the loop again +vm_ret: + ret r31, (r26) # if not a match, we're done +vm_end: lda r21, -1(r31) # get -1 + cmovne r20, r21, r0 # -1 if last char matched + ret r31, (r26) + + .set at + .set reorder + .end _OtsLocation diff --git a/private/crt32/misc/alpha/smove.s b/private/crt32/misc/alpha/smove.s new file mode 100644 index 000000000..7428e97a8 --- /dev/null +++ b/private/crt32/misc/alpha/smove.s @@ -0,0 +1,652 @@ + #++ + # Copyright 1991, 1994, Digital Equipment Corporation + # + # ots_move(char *dstptr INOUT, long dstlen, char *srcptr) + # + # Move dstlen characters from *srcptr to *dstptr, possibly overlapping + # + # Special conventions: No stack space, r16-r20 and r27-r28 ONLY, + # no linkage pointer required, r16 is INOUT and points to the address + # following the move. (Warning: The auto-loader potentially takes + # some regs across the call if this is being used in a shared lib. + # environment.) + # + # This is a GEM support routine for moving (possibly overlapping) memory + # from one address to another. This is optimized for extremely high + # performance both for small blocks and large moves. In order to reduce + # overhead for small cases, they are retired as quickly as possible, + # more case analysis is reserved for cases which will do more. Note + # that while overlapping moves are supported, (unlike Sys V memcpy) + # routines), they are not quite as fast. + # + # Warning - This code is basically "expanded microcode". Since it is + # executed so frequently in many contexts, it has been extensively "hand- + # optimized"... + # + # Note that this routine and ots_movem are basically similar in many + # respects (same basic code), so maintenance should be done both + # places. This routine is primarily provided for lower overhead (for + # short strings). + # + # This version of OTS_MOVE provides longword granularity. + # + # 015 30 Aug 1994 WBN Longword granularity version, based on + # OTS_MOVE_ALPHA.M64 version 014. + #-- + +#include "ots_defs.hs" + + # r16 = dst --> r16 = end + # r17 = len + # r18 = src + # destroys r17-r20, r27-r28 + + .globl _OtsMove + .ent _OtsMove +_OtsMove: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + beq r17, done # No memory accesses if length=0 + subq r17, 4, r20 # Get length-4 + ldq_u r28, (r18) # Load first QW of source + addq r17, r18, r27 # Point to end of source + andnot r16, 3, r19 # LW-aligned dst pointer + bge r20, geq4 # Go handle lengths >= 4 + ldq_u r27, -1(r27) # Load last QW of source + and r16, 3, r16 # Get dst alignment within LW + ldl r17, (r19) # Load first LW of destination + addq r20, r16, r20 # Get alignment+length-4 + extql r28, r18, r28 # Extract first bytes of source + bgt r20, double # Go handle LW crossing + extqh r27, r18, r27 # Extract last bytes of source + addq r20, 4, r20 # Get ending alignment in LW + or r27, r28, r28 # Combine halves of source + insql r28, r16, r28 # Position low part of source + mskql r17, r16, r18 # Keep low bytes of destination + mskql r28, r20, r28 # Trim off high bytes of source + mskqh r17, r20, r17 # Keep high bytes of destination + or r18, r28, r28 # Combine source with low dest + or r17, r28, r28 # Combine with high dest + stl r28, (r19) # Store to destination + addq r19, r20, r16 # Point to end of dest for return + ret r31, (r26) + +double: extqh r27, r18, r27 # Extract last bytes of source + ldl r18, 4(r19) # Load second LW of destination + mskql r17, r16, r17 # Keep low bytes of 1st dest LW + or r27, r28, r28 # Combine parts of source + insql r28, r16, r27 # Position start of source + addq r16, 4, r16 # Compute virtual start in LW + insqh r28, r16, r28 # Position end of source + addq r19, 4, r19 # Prepare to compute end address + mskqh r18, r20, r18 # Keep high bytes of 2nd dest LW + mskql r28, r20, r28 # Trim end of source to length + or r27, r17, r17 # Combine low source with 1st LW + stl r17, -4(r19) + or r28, r18, r18 # Combine high source with 2nd LW + stl r18, (r19) + addq r19, r20, r16 # Point to end of dest for return +done: ret r31, (r26) + + # Come here to move >= 4 bytes. + # + # r16-> dst + # r17 = length + # r18-> src + # r19-> LW-aligned dst + # r20 = len-4 + # r27 = src+len + # r28 = first src QW + +geq4: subq r20, 4, r17 # At least 8 bytes to move? + subq r16, r27, r27 # Check if dst >= src+len + blt r17, lss8 # Move 4..7 bytes + subq r18, r16, r17 # Check if src >= dst + bge r27, ok1 # Forward OK if whole src precedes dst + blt r17, reverse # Go backwards if src < dst < src+len +ok1: and r16, 7, r16 + addq r16, r20, r27 # Alignment + length - 4 + bne r16, part # Part of first QW to be skipped + subq r20, 4, r20 # At least 8 bytes to be stored? + beq r27, simple # Only low LW to be stored + and r18, 7, r27 # Is src address now aligned? + blt r20, shortq # Dst ends in first QW + subq r20, 32, r17 # At least 4 quadwords left to move? + beq r27, align # Go handle matching alignment + + # Src alignment differs from dst alignment. + # r16 = dst alignment + # r17 + # r18 = src-8 after 1st move + # r19 = initial dst + # r20 = initial length-8 + # r27 = dst QW if dst wasn't aligned + # r28 = source QW + +misal: or r16, r19, r19 # Put alignment back with dst ptr *** + ldq_u r17, 8(r18) # Load same or next source QW + extql r28, r18, r28 # Get first part of source to store + addq r20, r16, r20 # Adjust length for partial move + mskql r27, r19, r27 # Trim destination for merge + extqh r17, r18, r16 # Get second part of source + subq r20, 24, r20 # At least 4 more quadwords? + or r28, r16, r28 # Combine pieces of source + mskqh r28, r19, r28 # Trim low junk off source + andnot r19, 7, r19 # Adjust dst for partial move + bge r20, unrol2 # Taken branch for long strings + addq r20, 16, r16 # Add back: how many whole QW's? + nop +short2: and r20, 7, r20 # How many odd bytes? + blt r16, last # Skip if no more whole QW's + or r28, r27, r28 # Combine pieces + stq r28, (r19) + extql r17, r18, r27 # Get last part of prior src QW + ldq_u r17, 16(r18) # Load another src QW + addq r19, 8, r19 # Update dst + subq r16, 8, r16 # More whole QW's? + addq r18, 8, r18 # Update src + blt r16, lastx # Skip if no more whole QWs + extqh r17, r18, r28 # Get first part of this src QW + addq r18, 8, r18 # Update src again + or r28, r27, r28 # Combine pieces + stq r28, (r19) + extql r17, r18, r27 # Get last part of this src QW + ldq_u r17, 8(r18) # Load another src QW + addq r19, 8, r19 # Update dst +lastx: extqh r17, r18, r28 # Get first part of this src QW +last: addq r18, r20, r16 # Point to end-8 of src + beq r20, done_u # Skip if no odd bytes + or r28, r27, r28 # Combine parts of last whole QW + ldq_u r27, 7(r16) # Load final (maybe same) src QW + subq r20, 4, r16 # More than 4 bytes left? + stq r28, (r19) # Store last whole QW + extql r17, r18, r17 # Get last part of this src QW + extqh r27, r18, r27 # Get what we need from final src QW +joinx: ldq r28, 8(r19) # Load last QW of destination + or r17, r27, r27 # Combine pieces of source + mskql r27, r20, r27 # Trim to length + mskqh r28, r20, r28 # Make room in destination + bgt r16, done_u # Go store a whole QW + addq r20, 8, r20 # Increment length for return + or r28, r27, r28 # Insert src into dst + stl r28, 8(r19) # Final LW + addq r19, r20, r16 # Point to end of dst for return + ret r31, (r26) + + # Come here to move 4 thru 7 bytes. + # +lss8: addq r18, r17, r27 # Recover src+len-8 + and r16, 3, r16 # Dst alignment within LW + ldq_u r27, 7(r27) # Load last part of source + extql r28, r18, r28 # Extract first part of source + beq r16, lw # Handle LW-aligned dst + extqh r27, r18, r27 # Extract last part of source + ldl r18, (r19) # Load first LW of dst + addq r16, r20, r20 # align+len-4 of dst + or r28, r27, r28 # Complete source + mskql r28, r17, r28 # Trim source to length + mskql r18, r16, r18 # Make room in dst + insql r28, r16, r27 # Position src like dst + addq r16, r17, r17 # Align+len-8 of dst + or r27, r18, r18 # Merge + stl r18, (r19) # Store first LW of dst + extql r27, 4, r27 # Position next LW of src + blt r17, zz # Skip if not a whole LW + stl r27, 4(r19) # Store the whole LW + addq r19, 4, r19 # Adjust pointer + subq r20, 4, r20 # Adjust ending alignment + beq r17, donezz # Exit if done + insqh r28, r16, r27 # Position remainder of src +zz: ldl r28, 4(r19) # Load last dst LW + mskqh r28, r20, r28 # Make room in dst + or r28, r27, r27 # Merge + stl r27, 4(r19) # Final store +donezz: addq r19, r20, r16 # End address -4 + addq r16, 4, r16 + ret r31, (r26) + +lw: extqh r27, r18, r27 # Extract last part of source + addq r19, 4, r16 # Adjust for return value + beq r20, lwdone # Skip if exactly 4 bytes + ldl r17, 4(r19) # Load next dst LW + or r27, r28, r28 # Complete source + stl r28, (r19) # Store first LW + extql r28, 4, r28 # Position rest of source + mskqh r17, r20, r27 # Make room in dst + mskql r28, r20, r28 # Trim src + or r27, r28, r28 # Merge + stl r28, 4(r19) + addq r16, r20, r16 # Update return value + ret r31, (r26) + +lwdone: or r27, r28, r28 # Merge + stl r28, (r19) + ret r31, (r26) + + # Move 4 bytes to an aligned LW. + # +simple: ldq_u r27, 3(r18) # Load last QW of source + extql r28, r18, r28 # Position first QW + addq r19, 4, r16 # Point to end of dst for return + extqh r27, r18, r27 # Position last QW + or r28, r27, r28 # Merge + stl r28, (r19) # Store + ret r31, (r26) + + + # Dst is not aligned. Check whether first write is to a LW or a QW, + # and whether that finishes the move. Then see if src alignment + # matches, and read/rewrite the first dst quadword. + # + # r16 = dst alignment in QW + # r17 + # r18-> src + # r19-> LW-aligned dst + # r20 = len-4 + # r27 = QW_alignment + length - 4 + # r28 = first src QW + + #.align quad + +part: subq r27, 4, r17 # Does dst end in first QW? + ldq_u r27, (r19) # Load first dst QW + blt r17, shortu # Go handle short store + and r16, 4, r17 # Does it start in high LW? + subq r18, r16, r18 # Adjust src for this partial move + beq r17, quad # Whole QW to be touched + extql r28, r18, r17 # Position first part of source + ldq_u r28, 7(r18) # Get next (or same) src QW + mskql r27, r16, r27 # Trim destination for merge + addq r20, r16, r20 # Len + alignment... + extqh r28, r18, r28 # Position second part of source + subq r20, 4, r20 # Len+alignment-8 = remaining len + or r28, r17, r28 # Pieces of source + mskqh r28, r16, r17 # Trim junk preceding source + ldq_u r28, 7(r18) # Get src QW again ** + or r27, r17, r17 # Combine other source piece + extql r17, 4, r17 # Get the high LW + stl r17, (r19) # Store just that + + # Now at a QW boundary. Is there a QW left to store? + # Is the source QW aligned? + + andnot r19, 7, r19 # Adjust dst pointer to next-8 + subq r20, 8, r17 # Got a QW more? + and r18, 7, r27 # Src aligned? + blt r17, short3 # Too short + addq r19, 8, r19 + subq r20, 8, r20 + ldq_u r28, 8(r18) + addq r18, 8, r18 + subq r20, 32, r17 # Prepare for unrolled loop + beq r27, align # Alignment matches + or r31, r31, r27 + or r31, r31, r16 + br r31, misal + +shortu: addq r18, r20, r20 # Point to end-4 of src + ldq_u r20, 3(r20) # Get last QW of source + extql r28, r18, r28 # Fetch first QW of source + extqh r20, r18, r20 # Fetch last QW of source + mskql r27, r16, r18 # Clear from start thru end of dst + mskqh r27, r17, r27 # Clear from 0 to end of dst + or r28, r20, r28 # Combine src pieces + insql r28, r16, r28 # Position src + or r27, r18, r27 # Combine dst pieces + mskql r28, r17, r28 # Trim src + addq r19, r17, r20 # Final pointer for return + or r28, r27, r28 # Merge src & dst + stq_u r28, (r19) # Store it + addq r20, 8, r16 + ret r31, (r26) + +quad: and r18, 7, r17 # Is src address now aligned? + subq r20, 4, r20 # Get length-8 + bne r17, misal # Go handle mismatched alignment + mskqh r28, r16, r28 # Keep desired part of source + addq r20, r16, r20 # Adjust count for this partial move + mskql r27, r16, r27 # Keep desired part of destination QW + subq r20, 32, r17 # At least 4 quadwords left to move? + or r27, r28, r28 # Merge source and destination + + # Src alignment matches. + # r16 + # r17 = remaining length -32 + # r18 = next src pointer -8 + # r19 = dst pointer + # r20 + # r27 + # r28 = dst quadword + +align: and r17, 24, r20 # How many after a multiple of 4? + bge r17, unrol1 # Taken branch for long strings + nop +short1: and r17, 7, r17 # How many odd bytes? + beq r20, last28 # Skip if no more whole QWs after r28 + ldq r27, 8(r18) # Load next QW + addq r18, 8, r18 + stq r28, (r19) # Store prior QW + subq r20, 16, r20 # Map 8/16/24 to -8/0/8 + addq r19, 8, r19 + blt r20, last27 # Skip if no more after r27 + ldq r28, 8(r18) # Load next QW + addq r18, 8, r18 + stq r27, (r19) # Store prior QW + addq r19, 8, r19 + nop + beq r20, last28 + ldq r27, 8(r18) # Load next QW + addq r18, 8, r18 + stq r28, (r19) # Store prior QW + addq r19, 8, r19 +last27: beq r17, done27 # Skip if no odd bytes + ldq r28, 8(r18) # Load one more src QW + ldq r18, 8(r19) # Load last destination QW + subq r17, 4, r16 # More than 4 bytes to store? + stq r27, (r19) # Store prior QW + mskql r28, r17, r27 # Trim source + mskqh r18, r17, r18 # Trim destination + ble r16, lastl # Go store just a LW +lastq: addq r19, r17, r19 # End-8 of dst for return + or r27, r18, r27 # Merge src & dst +done27: stq_u r27, 7(r19) # Store last destination QW + addq r19, 8, r16 # End of dst for return + ret r31, (r26) + +short3: addq r18, r20, r16 # Point to end-8 of src + beq r20, donexx # Completely done? + ldq_u r17, 7(r16) # Load final src QW + subq r20, 4, r16 # Got more than a LW? + beq r27, joinx # Don't include prior src if aligned + extql r28, r18, r27 # Last part of prior src QW + extqh r17, r18, r17 # First part of this src QW + br joinx + +donexx: addq r19, r20, r16 + addq r16, 8, r16 + ret r31, (r26) + +last28: beq r17, done28 # Skip if no odd bytes + ldq r27, 8(r18) # Load one more src QW + ldq r18, 8(r19) # Load last destination QW + subq r17, 4, r16 # More than 4 bytes to store? + stq r28, (r19) # Store prior QW + mskql r27, r17, r27 # Trim source + mskqh r18, r17, r18 # Trim destination + bgt r16, lastq # Go store a QW +lastl: addq r17, 8, r17 # Increment length for return + or r27, r18, r27 # Merge src & dst + stl r27, 8(r19) # Store last destination LW + addq r19, r17, r16 # End of dst for return + ret r31, (r26) + +shortq: addq r18, r20, r16 # Point to end-8 of src + ldq r27, (r19) # Get dst QW + extql r28, r18, r28 # Position first src QW + ldq_u r17, 7(r16) # Get last QW of src + mskqh r27, r20, r27 # Mask dst QW + extqh r17, r18, r17 # Position last src QW + or r17, r28, r28 # Merge + mskql r28, r20, r28 # Trim src QW +done_u: addq r19, r20, r19 # End-8 of dst for return + or r28, r27, r28 # Combine pieces +done28: stq_u r28, 7(r19) # Store last destination QW + addq r19, 8, r16 # End of dst for return + ret r31, (r26) + + # Unrolled loop for long moves with matching alignment within QW. + # Each iteration moves two cache blocks. + # We try to schedule the cache misses to avoid a double miss + # in EV4 pass 2.1 chips. If the source alignment within a cache + # block is exactly 3, alter it, since that case runs slower. + # + # R19 = dst pointer + # R17 = remaining length (to load) - 32 + # R18 = src pointer + # R16 + # R20 = length & 24 (needed at return) + # R27 + # R28 = QW from 0(R18) to store at 0(R19), both on input and at return + # + + #.align quad + +unrol1: ldq r27, 32(r18) # Cache miss here; later loads hit. + subq r17, 48, r16 # Six more quadwords? + and r18, 16, r20 # Starting in 2nd half of cache block? + blt r16, uent1 # If not 6 more, don't adjust. + ldq r16, 8(r18) + beq r20, utop1 # If in 1st half, don't adjust. + ldq r27, 48(r18) # Cache miss here + addq r18, 16, r18 + stq r28, (r19) # Adjust by going ahead 1/2 block. + addq r19, 16, r19 + ldq r28, (r18) + subq r17, 16, r17 + stq r16, -8(r19) + nop + ldq r16, 8(r18) +utop1: subq r17, 32, r17 + +uloop1: ldq r20, 64(r18) # Cache miss here + stq r28, (r19) + ldq r28, 16(r18) + stq r16, 8(r19) + ldq r16, 24(r18) + addq r18, 64, r18 + stq r28, 16(r19) + mov r20, r28 + stq r16, 24(r19) + addq r19, 64, r19 + ldq r20, -24(r18) + subq r17, 32, r17 + blt r17, uexit1 + ldq r16, 32(r18) # Cache miss here + stq r27, -32(r19) + ldq r27, -16(r18) + stq r20, -24(r19) + ldq r20, -8(r18) + stq r27, -16(r19) + mov r16, r27 + stq r20, -8(r19) +uent1: subq r17, 32, r17 + ldq r16, 8(r18) + bge r17, uloop1 + + # finish last block of 4 quadwords + # +ubot1: stq r28, (r19) + mov r27, r28 # Position last QW for return + ldq r27, 16(r18) + addq r18, 32, r18 + stq r16, 8(r19) + addq r19, 32, r19 +uex1a: ldq r16, -8(r18) + and r17, 24, r20 # Recover count of remaining QW's + stq r27, -16(r19) + stq r16, -8(r19) + br r31, short1 + + nop +uexit1: stq r27, -32(r19) # Here if exit from middle of loop + ldq r27, -16(r18) + stq r20, -24(r19) + br r31, uex1a # Join common exit sequence + + #.align quad + +unrol2: ldq_u r16, 16(r18) # Load next src QW + extql r17, r18, r17 # Get last part of prior one + or r28, r27, r28 # Combine pieces + stq r28, (r19) # Store prior dst QW + subq r20, 24, r20 # Update loop counter + extqh r16, r18, r28 # Get first part of a src QW + ldq_u r27, 24(r18) # Load next src QW + extql r16, r18, r16 # Get last part of prior one + or r28, r17, r28 # Combine pieces + stq r28, 8(r19) # Store prior dst QW + addq r19, 24, r19 # Update dst pointer + extqh r27, r18, r28 # Get first part of a src QW + ldq_u r17, 32(r18) # Load next src QW + extql r27, r18, r27 # Get last part of prior one + or r28, r16, r28 # Combine pieces + stq r28, -8(r19) # Store prior dst QW + addq r18, 24, r18 # Update src pointer + extqh r17, r18, r28 # Get first part of a src QW + bge r20, unrol2 # Repeat as needed + addq r20, 16, r16 # How many whole quadwords left? + br r31, short2 # Go handle leftovers + nop + + # Must move in reverse order because of overlap. + # r16 = dst address + # r17 + # r18 = src address + # r19 + # r20 = len-4 (>= 0) + # r27 + # r28 + + # Not yet LW-granularity... + +reverse: + subq r20, 4, r20 # This code expects len-8 + addq r20, r18, r18 # Point to end-8 of source + addq r20, r16, r17 # Point to end-8 of destination + and r17, 7, r19 # Is destination aligned? + ldq_u r28, 7(r18) # Get source QW + addq r17, 8, r16 # Point to end of dst for return + bne r19, rpart # Skip if partial write needed + and r18, 7, r27 # Is source aligned too? + beq r27, ralign # Skip if so + ldq_u r19, (r18) # Handle aligned dst, unaligned src + subq r20, 8, r20 + extqh r28, r18, r28 + extql r19, r18, r27 + br r31, rwhole + +rmis: ldq_u r19, (r18) # Load same or preceding src QW + extqh r28, r18, r28 # Get last part of source to store + mskqh r27, r16, r27 # Keep high-address part of dst + extql r19, r18, r19 + subq r20, 8, r20 # How many more whole QW's? + or r19, r28, r28 + ldq_u r19, (r18) # Reload source QW + mskql r28, r16, r28 # Trim source to length +rwhole: blt r20, rlast2 # Skip if no more whole QW's +rloop2: or r28, r27, r28 # Combine pieces + stq r28, (r17) +rent2: extqh r19, r18, r27 + ldq_u r19, -8(r18) + subq r20, 8, r20 + subq r17, 8, r17 + extql r19, r18, r28 + subq r18, 8, r18 + bge r20, rloop2 +rlast2: and r20, 7, r20 + beq r20, rdone2 + or r28, r27, r28 + subq r18, r20, r27 + stq r28, (r17) +rl2ent: subq r31, r20, r20 + ldq_u r27, (r27) + extqh r19, r18, r19 + ldq r28, -8(r17) + subq r17, 8, r17 + extql r27, r18, r27 + mskql r28, r20, r28 + or r27, r19, r27 + mskqh r27, r20, r27 + and r20, 4, r19 # Ending in high LW? + bne r19, rdone3 # Only longword store at the end +rdone2: or r28, r27, r28 + stq r28, (r17) + ret r31, (r26) + +rdone3: or r28, r27, r28 + extql r28, 4, r28 + stl r28, 4(r17) + ret r31, (r26) + +rpart: ldq_u r27, 7(r17) # Get dst QW + subq r19, 8, r19 # Get negative of bytes not moved + subq r18, r19, r18 # From src-8, get src after partial + subq r20, r19, r20 # Adjust length for partial move + subq r17, r19, r17 # Adjust dst pointer + addq r19, 4, r19 # End alignment - 4 + ble r19, r_lw # Only storing the low longword? + and r18, 7, r19 # Src alignment now matching dst? + bne r19, rmis # Go back if not + mskql r28, r16, r28 # Keep low addresses of src QW + mskqh r27, r16, r27 # Keep high address of dst QW +ralign: subq r20, 8, r20 # How many more whole QW's? + or r27, r28, r28 # Combine + blt r20, rlast1 # Skip if this is the end +rloop1: stq r28, (r17) # Store one QW +rent1: subq r20, 8, r20 # Decrement length + ldq r28, -8(r18) # Load preceding QW + subq r17, 8, r17 # Decrement dst pointer + subq r18, 8, r18 # Decrement src pointer + bge r20, rloop1 # Repeat for each whole QW +rlast1: and r20, 7, r20 # How many odd bytes? + beq r20, rdone # Skip if none + ldq r27, -8(r18) # Get another source QW + subq r31, r20, r20 # Get byte # to end at + stq r28, (r17) +rl_ent: ldq r28, -8(r17) + subq r17, 8, r17 # Adjust dst pointer again + mskqh r27, r20, r27 # Keep top of src QW + and r20, 4, r19 # Ending in high LW? + mskql r28, r20, r28 # Keep bottom of dst QW + bne r19, rdone4 # Only longword store at the end + or r27, r28, r28 # Combine +rdone: stq r28, (r17) # Store last QW + ret r31, (r26) + +rdone4: or r27, r28, r28 # Combine + extql r28, 4, r28 # Get high part + stl r28, 4(r17) # Store last LW + ret r31, (r26) + +r_lw: and r18, 7, r19 # Src alignment now matching dst? + bne r19, rmislw # Go back if not + mskql r28, r16, r28 # Keep low addresses of src QW + mskqh r27, r16, r27 # Keep high address of dst QW + subq r20, 8, r20 # How many more whole QW's? + or r27, r28, r28 # Combine + blt r20, rlast1_lw # Skip if this is the end + stl r28, (r17) # Store one QW + br r31, rent1 + +rlast1_lw: + and r20, 7, r20 # How many odd bytes? + ldq r27, -8(r18) # Get another source QW + subq r31, r20, r20 # Get byte # to end at + stl r28, (r17) + br rl_ent + +rmislw: ldq_u r19, (r18) # Load same or preceding src QW + extqh r28, r18, r28 # Get last part of source to store + mskqh r27, r16, r27 # Keep high-address part of dst + extql r19, r18, r19 + subq r20, 8, r20 # How many more whole QW's? + or r19, r28, r28 + ldq_u r19, (r18) # Reload source QW + mskql r28, r16, r28 # Trim source to length + blt r20, rlast2_lw # Skip if no more whole QW's + or r28, r27, r28 # Combine pieces + stl r28, (r17) + br r31, rent2 + +rlast2_lw: + and r20, 7, r20 + or r28, r27, r28 + subq r18, r20, r27 + stl r28, (r17) + br r31, rl2ent + + .set at + .set reorder + .end _OtsMove diff --git a/private/crt32/misc/alpha/smovem.s b/private/crt32/misc/alpha/smovem.s new file mode 100644 index 000000000..11f859f20 --- /dev/null +++ b/private/crt32/misc/alpha/smovem.s @@ -0,0 +1,667 @@ + #++ + # Copyright 1991, 1994, Digital Equipment Corporation + # + # ots_movem(char *dstptr INOUT, long dstlen INOUT, + # char *srcptr, long srclen) + # + # Move dstlen characters from *srcptr to *dstptr, possibly overlapping + # + # Special conventions: No stack space, r16-r21 and r27-r28 ONLY, + # no linkage pointer required, r16 is INOUT and points to the address + # following the move, r17 is INOUT and has the remaining destination + # length following the move. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # This is a GEM support routine for moving (possibly overlapping) memory + # from one address to another. This is optimized for extremely high + # performance both for small blocks and large moves. In order to reduce + # overhead for small cases, they are retired as quickly as possible, + # more case analysis is reserved for cases which will do more. Note + # that while overlapping moves are supported, (unlike Sys V memcpy) + # routines), they are not quite as fast. + # + # Warning - This code is basically "expanded microcode". Since it is + # executed so frequently in many contexts, it has been extensively "hand- + # optimized"... + # + # Note that this routine and ots_move are basically similar in many + # respects (same basic code), so maintenance should be done both + # places. This routine is primarily provided for lower overhead (for + # short strings). + # [Except for the first few instructions, the recipe for creating OTS_MOVEM + # from OTS_MOVE is to change uses of R19->R21 and then R17->R19.] + # + # This version of OTS_MOVEM provides longword granularity. + # + # 015 1 Sep 1994 WBN Longword granularity version, based on + # OTS_MOVEM_ALPHA.M64 version 014 and + # OTS_MOVE_ALPHA_WNT.M64 version 015. + #-- + +#include "ots_defs.hs" + + # r16 = dst --> r16 = end + # r19 = dst_len --> r17 = remaining + # r18 = src + # r19 = src_len + # destroys r18-r21, r27-r28 + + .globl _OtsMoveMinimum + .ent _OtsMoveMinimum +_OtsMoveMinimum: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + subq r17, r19, r20 # Which length is larger? + cmovlt r20, r17, r19 # Min to r19 + andnot r16, 3, r21 # LW-aligned dst pointer + subq r19, 4, r20 # Get length-4 + beq r19, done # No memory accesses if length=0 + ldq_u r28, (r18) # Load first QW of source + addq r19, r18, r27 # Point to end of source + subq r17, r19, r17 # Set remaining length for return + bge r20, geq4 # Go handle lengths >= 4 + ldq_u r27, -1(r27) # Load last QW of source + and r16, 3, r16 # Get dst alignment within LW + ldl r19, (r21) # Load first LW of destination + addq r20, r16, r20 # Get alignment+length-4 + extql r28, r18, r28 # Extract first bytes of source + bgt r20, double # Go handle LW crossing + extqh r27, r18, r27 # Extract last bytes of source + addq r20, 4, r20 # Get ending alignment in LW + or r27, r28, r28 # Combine halves of source + insql r28, r16, r28 # Position low part of source + mskql r19, r16, r18 # Keep low bytes of destination + mskql r28, r20, r28 # Trim off high bytes of source + mskqh r19, r20, r19 # Keep high bytes of destination + or r18, r28, r28 # Combine source with low dest + or r19, r28, r28 # Combine with high dest + stl r28, (r21) # Store to destination + addq r21, r20, r16 # Point to end of dest for return + ret r31, (r26) + +double: extqh r27, r18, r27 # Extract last bytes of source + ldl r18, 4(r21) # Load second LW of destination + mskql r19, r16, r19 # Keep low bytes of 1st dest LW + or r27, r28, r28 # Combine parts of source + insql r28, r16, r27 # Position start of source + addq r16, 4, r16 # Compute virtual start in LW + insqh r28, r16, r28 # Position end of source + addq r21, 4, r21 # Prepare to compute end address + mskqh r18, r20, r18 # Keep high bytes of 2nd dest LW + mskql r28, r20, r28 # Trim end of source to length + or r27, r19, r19 # Combine low source with 1st LW + stl r19, -4(r21) + or r28, r18, r18 # Combine high source with 2nd LW + stl r18, (r21) + addq r21, r20, r16 # Point to end of dest for return +done: ret r31, (r26) + + # Come here to move >= 4 bytes. + # + # r16-> dst + # r17 = remaining length for return + # r18-> src + # r19 = length + # r20 = len-4 + # r21-> LW-aligned dst + # r27 = src+len + # r28 = first src QW + +geq4: subq r20, 4, r19 # At least 8 bytes to move? + subq r16, r27, r27 # Check if dst >= src+len + blt r19, lss8 # Move 4..7 bytes + subq r18, r16, r19 # Check if src >= dst + bge r27, ok1 # Forward OK if whole src precedes dst + blt r19, reverse # Go backwards if src < dst < src+len +ok1: and r16, 7, r16 + addq r16, r20, r27 # Alignment + length - 4 + bne r16, part # Part of first QW to be skipped + subq r20, 4, r20 # At least 8 bytes to be stored? + beq r27, simple # Only low LW to be stored + and r18, 7, r27 # Is src address now aligned? + blt r20, shortq # Dst ends in first QW + subq r20, 32, r19 # At least 4 quadwords left to move? + beq r27, align # Go handle matching alignment + + # Src alignment differs from dst alignment. + # r16 = dst alignment + # r17 = remaining length for return + # r18 = src-8 after 1st move + # r19 + # r20 = initial length-8 + # r21 = initial dst + # r27 = dst QW if dst wasn't aligned + # r28 = source QW + +misal: or r16, r21, r21 # Put alignment back with dst ptr *** + ldq_u r19, 8(r18) # Load same or next source QW + extql r28, r18, r28 # Get first part of source to store + addq r20, r16, r20 # Adjust length for partial move + mskql r27, r21, r27 # Trim destination for merge + extqh r19, r18, r16 # Get second part of source + subq r20, 24, r20 # At least 4 more quadwords? + or r28, r16, r28 # Combine pieces of source + mskqh r28, r21, r28 # Trim low junk off source + andnot r21, 7, r21 # Adjust dst for partial move + bge r20, unrol2 # Taken branch for long strings + addq r20, 16, r16 # Add back: how many whole QW's? + nop +short2: and r20, 7, r20 # How many odd bytes? + blt r16, last # Skip if no more whole QW's + or r28, r27, r28 # Combine pieces + stq r28, (r21) + extql r19, r18, r27 # Get last part of prior src QW + ldq_u r19, 16(r18) # Load another src QW + addq r21, 8, r21 # Update dst + subq r16, 8, r16 # More whole QW's? + addq r18, 8, r18 # Update src + blt r16, lastx # Skip if no more whole QWs + extqh r19, r18, r28 # Get first part of this src QW + addq r18, 8, r18 # Update src again + or r28, r27, r28 # Combine pieces + stq r28, (r21) + extql r19, r18, r27 # Get last part of this src QW + ldq_u r19, 8(r18) # Load another src QW + addq r21, 8, r21 # Update dst +lastx: extqh r19, r18, r28 # Get first part of this src QW +last: addq r18, r20, r16 # Point to end-8 of src + beq r20, done_u # Skip if no odd bytes + or r28, r27, r28 # Combine parts of last whole QW + ldq_u r27, 7(r16) # Load final (maybe same) src QW + subq r20, 4, r16 # More than 4 bytes left? + stq r28, (r21) # Store last whole QW + extql r19, r18, r19 # Get last part of this src QW + extqh r27, r18, r27 # Get what we need from final src QW +joinx: ldq r28, 8(r21) # Load last QW of destination + or r19, r27, r27 # Combine pieces of source + mskql r27, r20, r27 # Trim to length + mskqh r28, r20, r28 # Make room in destination + bgt r16, done_u # Go store a whole QW + addq r20, 8, r20 # Increment length for return + or r28, r27, r28 # Insert src into dst + stl r28, 8(r21) # Final LW + addq r21, r20, r16 # Point to end of dst for return + ret r31, (r26) + + # Come here to move 4 thru 7 bytes. + # +lss8: addq r18, r19, r27 # Recover src+len-8 + and r16, 3, r16 # Dst alignment within LW + ldq_u r27, 7(r27) # Load last part of source + extql r28, r18, r28 # Extract first part of source + beq r16, lw # Handle LW-aligned dst + extqh r27, r18, r27 # Extract last part of source + ldl r18, (r21) # Load first LW of dst + addq r16, r20, r20 # align+len-4 of dst + or r28, r27, r28 # Complete source + mskql r28, r19, r28 # Trim source to length + mskql r18, r16, r18 # Make room in dst + insql r28, r16, r27 # Position src like dst + addq r16, r19, r19 # Align+len-8 of dst + or r27, r18, r18 # Merge + stl r18, (r21) # Store first LW of dst + extql r27, 4, r27 # Position next LW of src + blt r19, zz # Skip if not a whole LW + stl r27, 4(r21) # Store the whole LW + addq r21, 4, r21 # Adjust pointer + subq r20, 4, r20 # Adjust ending alignment + beq r19, donezz # Exit if done + insqh r28, r16, r27 # Position remainder of src +zz: ldl r28, 4(r21) # Load last dst LW + mskqh r28, r20, r28 # Make room in dst + or r28, r27, r27 # Merge + stl r27, 4(r21) # Final store +donezz: addq r21, r20, r16 # End address -4 + addq r16, 4, r16 + ret r31, (r26) + +lw: extqh r27, r18, r27 # Extract last part of source + addq r21, 4, r16 # Adjust for return value + beq r20, lwdone # Skip if exactly 4 bytes + ldl r19, 4(r21) # Load next dst LW + or r27, r28, r28 # Complete source + stl r28, (r21) # Store first LW + extql r28, 4, r28 # Position rest of source + mskqh r19, r20, r27 # Make room in dst + mskql r28, r20, r28 # Trim src + or r27, r28, r28 # Merge + stl r28, 4(r21) + addq r16, r20, r16 # Update return value + ret r31, (r26) + +lwdone: or r27, r28, r28 # Merge + stl r28, (r21) + ret r31, (r26) + + # Move 4 bytes to an aligned LW. + # +simple: ldq_u r27, 3(r18) # Load last QW of source + extql r28, r18, r28 # Position first QW + addq r21, 4, r16 # Point to end of dst for return + extqh r27, r18, r27 # Position last QW + or r28, r27, r28 # Merge + stl r28, (r21) # Store + ret r31, (r26) + + + # Dst is not aligned. Check whether first write is to a LW or a QW, + # and whether that finishes the move. Then see if src alignment + # matches, and read/rewrite the first dst quadword. + # + # r16 = dst alignment in QW + # r17 = remaining length for return + # r18-> src + # r19 + # r20 = len-4 + # r21-> LW-aligned dst + # r27 = QW_alignment + length - 4 + # r28 = first src QW + + #.align quad + +part: subq r27, 4, r19 # Does dst end in first QW? + ldq_u r27, (r21) # Load first dst QW + blt r19, shortu # Go handle short store + and r16, 4, r19 # Does it start in high LW? + subq r18, r16, r18 # Adjust src for this partial move + beq r19, quad # Whole QW to be touched + extql r28, r18, r19 # Position first part of source + ldq_u r28, 7(r18) # Get next (or same) src QW + mskql r27, r16, r27 # Trim destination for merge + addq r20, r16, r20 # Len + alignment... + extqh r28, r18, r28 # Position second part of source + subq r20, 4, r20 # Len+alignment-8 = remaining len + or r28, r19, r28 # Pieces of source + mskqh r28, r16, r19 # Trim junk preceding source + ldq_u r28, 7(r18) # Get src QW again ** + or r27, r19, r19 # Combine other source piece + extql r19, 4, r19 # Get the high LW + stl r19, (r21) # Store just that + + # Now at a QW boundary. Is there a QW left to store? + # Is the source QW aligned? + + andnot r21, 7, r21 # Adjust dst pointer to next-8 + subq r20, 8, r19 # Got a QW more? + and r18, 7, r27 # Src aligned? + blt r19, short3 # Too short + addq r21, 8, r21 + subq r20, 8, r20 + ldq_u r28, 8(r18) + addq r18, 8, r18 + subq r20, 32, r19 # Prepare for unrolled loop + beq r27, align # Alignment matches + or r31, r31, r27 + or r31, r31, r16 + br r31, misal + +shortu: addq r18, r20, r20 # Point to end-4 of src + ldq_u r20, 3(r20) # Get last QW of source + extql r28, r18, r28 # Fetch first QW of source + extqh r20, r18, r20 # Fetch last QW of source + mskql r27, r16, r18 # Clear from start thru end of dst + mskqh r27, r19, r27 # Clear from 0 to end of dst + or r28, r20, r28 # Combine src pieces + insql r28, r16, r28 # Position src + or r27, r18, r27 # Combine dst pieces + mskql r28, r19, r28 # Trim src + addq r21, r19, r20 # Final pointer for return + or r28, r27, r28 # Merge src & dst + stq_u r28, (r21) # Store it + addq r20, 8, r16 + ret r31, (r26) + +quad: and r18, 7, r19 # Is src address now aligned? + subq r20, 4, r20 # Get length-8 + bne r19, misal # Go handle mismatched alignment + mskqh r28, r16, r28 # Keep desired part of source + addq r20, r16, r20 # Adjust count for this partial move + mskql r27, r16, r27 # Keep desired part of destination QW + subq r20, 32, r19 # At least 4 quadwords left to move? + or r27, r28, r28 # Merge source and destination + + # Src alignment matches. + # r16 + # r17 = remaining length for return + # r18 = next src pointer -8 + # r19 = remaining length -32 + # r20 + # r21 = dst pointer + # r27 + # r28 = dst quadword + +align: and r19, 24, r20 # How many after a multiple of 4? + bge r19, unrol1 # Taken branch for long strings + nop +short1: and r19, 7, r19 # How many odd bytes? + beq r20, last28 # Skip if no more whole QWs after r28 + ldq r27, 8(r18) # Load next QW + addq r18, 8, r18 + stq r28, (r21) # Store prior QW + subq r20, 16, r20 # Map 8/16/24 to -8/0/8 + addq r21, 8, r21 + blt r20, last27 # Skip if no more after r27 + ldq r28, 8(r18) # Load next QW + addq r18, 8, r18 + stq r27, (r21) # Store prior QW + addq r21, 8, r21 + nop + beq r20, last28 + ldq r27, 8(r18) # Load next QW + addq r18, 8, r18 + stq r28, (r21) # Store prior QW + addq r21, 8, r21 +last27: beq r19, done27 # Skip if no odd bytes + ldq r28, 8(r18) # Load one more src QW + ldq r18, 8(r21) # Load last destination QW + subq r19, 4, r16 # More than 4 bytes to store? + stq r27, (r21) # Store prior QW + mskql r28, r19, r27 # Trim source + mskqh r18, r19, r18 # Trim destination + ble r16, lastl # Go store just a LW +lastq: addq r21, r19, r21 # End-8 of dst for return + or r27, r18, r27 # Merge src & dst +done27: stq_u r27, 7(r21) # Store last destination QW + addq r21, 8, r16 # End of dst for return + ret r31, (r26) + +short3: addq r18, r20, r16 # Point to end-8 of src + beq r20, donexx # Completely done? + ldq_u r19, 7(r16) # Load final src QW + subq r20, 4, r16 # Got more than a LW? + beq r27, joinx # Don't include prior src if aligned + extql r28, r18, r27 # Last part of prior src QW + extqh r19, r18, r19 # First part of this src QW + br joinx + +donexx: addq r21, r20, r16 + addq r16, 8, r16 + ret r31, (r26) + +last28: beq r19, done28 # Skip if no odd bytes + ldq r27, 8(r18) # Load one more src QW + ldq r18, 8(r21) # Load last destination QW + subq r19, 4, r16 # More than 4 bytes to store? + stq r28, (r21) # Store prior QW + mskql r27, r19, r27 # Trim source + mskqh r18, r19, r18 # Trim destination + bgt r16, lastq # Go store a QW +lastl: addq r19, 8, r19 # Increment length for return + or r27, r18, r27 # Merge src & dst + stl r27, 8(r21) # Store last destination LW + addq r21, r19, r16 # End of dst for return + ret r31, (r26) + +shortq: addq r18, r20, r16 # Point to end-8 of src + ldq r27, (r21) # Get dst QW + extql r28, r18, r28 # Position first src QW + ldq_u r19, 7(r16) # Get last QW of src + mskqh r27, r20, r27 # Mask dst QW + extqh r19, r18, r19 # Position last src QW + or r19, r28, r28 # Merge + mskql r28, r20, r28 # Trim src QW +done_u: addq r21, r20, r21 # End-8 of dst for return + or r28, r27, r28 # Combine pieces +done28: stq_u r28, 7(r21) # Store last destination QW + addq r21, 8, r16 # End of dst for return + ret r31, (r26) + + # Unrolled loop for long moves with matching alignment within QW. + # Each iteration moves two cache blocks. + # We try to schedule the cache misses to avoid a double miss + # in EV4 pass 2.1 chips. If the source alignment within a cache + # block is exactly 3, alter it, since that case runs slower. + # + # R16 + # R17 = remaining length for return + # R18 = src pointer + # R19 = remaining length (to load) - 32 + # R20 = length & 24 (needed at return) + # R21 = dst pointer + # R27 + # R28 = QW from 0(R18) to store at 0(R21), both on input and at return + # + + #.align quad + +unrol1: ldq r27, 32(r18) # Cache miss here; later loads hit. + subq r19, 48, r16 # Six more quadwords? + and r18, 16, r20 # Starting in 2nd half of cache block? + blt r16, uent1 # If not 6 more, don't adjust. + ldq r16, 8(r18) + beq r20, utop1 # If in 1st half, don't adjust. + ldq r27, 48(r18) # Cache miss here + addq r18, 16, r18 + stq r28, (r21) # Adjust by going ahead 1/2 block. + addq r21, 16, r21 + ldq r28, (r18) + subq r19, 16, r19 + stq r16, -8(r21) + nop + ldq r16, 8(r18) +utop1: subq r19, 32, r19 + +uloop1: ldq r20, 64(r18) # Cache miss here + stq r28, (r21) + ldq r28, 16(r18) + stq r16, 8(r21) + ldq r16, 24(r18) + addq r18, 64, r18 + stq r28, 16(r21) + mov r20, r28 + stq r16, 24(r21) + addq r21, 64, r21 + ldq r20, -24(r18) + subq r19, 32, r19 + blt r19, uexit1 + ldq r16, 32(r18) # Cache miss here + stq r27, -32(r21) + ldq r27, -16(r18) + stq r20, -24(r21) + ldq r20, -8(r18) + stq r27, -16(r21) + mov r16, r27 + stq r20, -8(r21) +uent1: subq r19, 32, r19 + ldq r16, 8(r18) + bge r19, uloop1 + + # finish last block of 4 quadwords + # +ubot1: stq r28, (r21) + mov r27, r28 # Position last QW for return + ldq r27, 16(r18) + addq r18, 32, r18 + stq r16, 8(r21) + addq r21, 32, r21 +uex1a: ldq r16, -8(r18) + and r19, 24, r20 # Recover count of remaining QW's + stq r27, -16(r21) + stq r16, -8(r21) + br r31, short1 + + nop +uexit1: stq r27, -32(r21) # Here if exit from middle of loop + ldq r27, -16(r18) + stq r20, -24(r21) + br r31, uex1a # Join common exit sequence + + #.align quad + +unrol2: ldq_u r16, 16(r18) # Load next src QW + extql r19, r18, r19 # Get last part of prior one + or r28, r27, r28 # Combine pieces + stq r28, (r21) # Store prior dst QW + subq r20, 24, r20 # Update loop counter + extqh r16, r18, r28 # Get first part of a src QW + ldq_u r27, 24(r18) # Load next src QW + extql r16, r18, r16 # Get last part of prior one + or r28, r19, r28 # Combine pieces + stq r28, 8(r21) # Store prior dst QW + addq r21, 24, r21 # Update dst pointer + extqh r27, r18, r28 # Get first part of a src QW + ldq_u r19, 32(r18) # Load next src QW + extql r27, r18, r27 # Get last part of prior one + or r28, r16, r28 # Combine pieces + stq r28, -8(r21) # Store prior dst QW + addq r18, 24, r18 # Update src pointer + extqh r19, r18, r28 # Get first part of a src QW + bge r20, unrol2 # Repeat as needed + addq r20, 16, r16 # How many whole quadwords left? + br r31, short2 # Go handle leftovers + nop + + # Must move in reverse order because of overlap. + # r16 = dst address + # r17 = remaining length for return + # r18 = src address + # r19 + # r20 = len-4 (>= 0) + # r21 + # r27 + # r28 + + # Not yet LW-granularity... + +reverse: + subq r20, 4, r20 # This code expects len-8 + addq r20, r18, r18 # Point to end-8 of source + addq r20, r16, r19 # Point to end-8 of destination + and r19, 7, r21 # Is destination aligned? + ldq_u r28, 7(r18) # Get source QW + addq r19, 8, r16 # Point to end of dst for return + bne r21, rpart # Skip if partial write needed + and r18, 7, r27 # Is source aligned too? + beq r27, ralign # Skip if so + ldq_u r21, (r18) # Handle aligned dst, unaligned src + subq r20, 8, r20 + extqh r28, r18, r28 + extql r21, r18, r27 + br r31, rwhole + +rmis: ldq_u r21, (r18) # Load same or preceding src QW + extqh r28, r18, r28 # Get last part of source to store + mskqh r27, r16, r27 # Keep high-address part of dst + extql r21, r18, r21 + subq r20, 8, r20 # How many more whole QW's? + or r21, r28, r28 + ldq_u r21, (r18) # Reload source QW + mskql r28, r16, r28 # Trim source to length +rwhole: blt r20, rlast2 # Skip if no more whole QW's +rloop2: or r28, r27, r28 # Combine pieces + stq r28, (r19) +rent2: extqh r21, r18, r27 + ldq_u r21, -8(r18) + subq r20, 8, r20 + subq r19, 8, r19 + extql r21, r18, r28 + subq r18, 8, r18 + bge r20, rloop2 +rlast2: and r20, 7, r20 + beq r20, rdone2 + or r28, r27, r28 + subq r18, r20, r27 + stq r28, (r19) +rl2ent: subq r31, r20, r20 + ldq_u r27, (r27) + extqh r21, r18, r21 + ldq r28, -8(r19) + subq r19, 8, r19 + extql r27, r18, r27 + mskql r28, r20, r28 + or r27, r21, r27 + mskqh r27, r20, r27 + and r20, 4, r21 # Ending in high LW? + bne r21, rdone3 # Only longword store at the end +rdone2: or r28, r27, r28 + stq r28, (r19) + ret r31, (r26) + +rdone3: or r28, r27, r28 + extql r28, 4, r28 + stl r28, 4(r19) + ret r31, (r26) + +rpart: ldq_u r27, 7(r19) # Get dst QW + subq r21, 8, r21 # Get negative of bytes not moved + subq r18, r21, r18 # From src-8, get src after partial + subq r20, r21, r20 # Adjust length for partial move + subq r19, r21, r19 # Adjust dst pointer + addq r21, 4, r21 # End alignment - 4 + ble r21, r_lw # Only storing the low longword? + and r18, 7, r21 # Src alignment now matching dst? + bne r21, rmis # Go back if not + mskql r28, r16, r28 # Keep low addresses of src QW + mskqh r27, r16, r27 # Keep high address of dst QW +ralign: subq r20, 8, r20 # How many more whole QW's? + or r27, r28, r28 # Combine + blt r20, rlast1 # Skip if this is the end +rloop1: stq r28, (r19) # Store one QW +rent1: subq r20, 8, r20 # Decrement length + ldq r28, -8(r18) # Load preceding QW + subq r19, 8, r19 # Decrement dst pointer + subq r18, 8, r18 # Decrement src pointer + bge r20, rloop1 # Repeat for each whole QW +rlast1: and r20, 7, r20 # How many odd bytes? + beq r20, rdone # Skip if none + ldq r27, -8(r18) # Get another source QW + subq r31, r20, r20 # Get byte # to end at + stq r28, (r19) +rl_ent: ldq r28, -8(r19) + subq r19, 8, r19 # Adjust dst pointer again + mskqh r27, r20, r27 # Keep top of src QW + and r20, 4, r21 # Ending in high LW? + mskql r28, r20, r28 # Keep bottom of dst QW + bne r21, rdone4 # Only longword store at the end + or r27, r28, r28 # Combine +rdone: stq r28, (r19) # Store last QW + ret r31, (r26) + +rdone4: or r27, r28, r28 # Combine + extql r28, 4, r28 # Get high part + stl r28, 4(r19) # Store last LW + ret r31, (r26) + +r_lw: and r18, 7, r21 # Src alignment now matching dst? + bne r21, rmislw # Go back if not + mskql r28, r16, r28 # Keep low addresses of src QW + mskqh r27, r16, r27 # Keep high address of dst QW + subq r20, 8, r20 # How many more whole QW's? + or r27, r28, r28 # Combine + blt r20, rlast1_lw # Skip if this is the end + stl r28, (r19) # Store one QW + br r31, rent1 + +rlast1_lw: + and r20, 7, r20 # How many odd bytes? + ldq r27, -8(r18) # Get another source QW + subq r31, r20, r20 # Get byte # to end at + stl r28, (r19) + br rl_ent + +rmislw: ldq_u r21, (r18) # Load same or preceding src QW + extqh r28, r18, r28 # Get last part of source to store + mskqh r27, r16, r27 # Keep high-address part of dst + extql r21, r18, r21 + subq r20, 8, r20 # How many more whole QW's? + or r21, r28, r28 + ldq_u r21, (r18) # Reload source QW + mskql r28, r16, r28 # Trim source to length + blt r20, rlast2_lw # Skip if no more whole QW's + or r28, r27, r28 # Combine pieces + stl r28, (r19) + br r31, rent2 + +rlast2_lw: + and r20, 7, r20 + or r28, r27, r28 + subq r18, r20, r27 + stl r28, (r19) + br r31, rl2ent + + .set at + .set reorder + .end _OtsMove diff --git a/private/crt32/misc/alpha/strans.s b/private/crt32/misc/alpha/strans.s new file mode 100644 index 000000000..9c738dce7 --- /dev/null +++ b/private/crt32/misc/alpha/strans.s @@ -0,0 +1,122 @@ + #++ + # + # Copyright (c) 1993 by + # Digital Equipment Corporation, Maynard, MA + # + # This software is furnished under a license and may be used and copied + # only in accordance with the terms of such license and with the + # inclusion of the above copyright notice. This software or any other + # copies thereof may not be provided or otherwise made available to any + # other person. No title to and ownership of the software is hereby + # transferred. + # + # The information in this software is subject to change without notice + # and should not be construed as a commitment by Digital Equipment + # Corporation. + # + # Digital assumes no responsibility for the use or reliability of its + # software on equipment which is not supplied by Digital. + # + + # Facility: + # + # GEM/OTS - GEM compiler system support library + # + # Abstract: + # + # OTS character string support, Alpha version + # + # Authors: + # + # Kent Glossop + # + # void ots_translate(char *dst, long dstlen, char *src, char table[256]); + # + # Translates a string using a translation table. Handles overlap. + # + # Special conventions: No stack space, r16-r21 and r26-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # Modification history: + # + # 006 13 Nov 1992 KDG Initial non-tailored assembly version, + # replacing BLISS -005 + # + # 007 26 Jan 1993 KDG Add underscore + #-- + +#include "ots_defs.hs" + + # r16 destination address + # r17 length + # r18 source address + # r19 table address + # r20,r21,r27,r28 scratch + # r26 return address + # + .globl _OtsStringTranslate + .ent _OtsStringTranslate +_OtsStringTranslate: + .set noat + .set noreorder + .frame sp,0,r26 + + # sort out which case to use + addq r18, r17, r27 # get end address of source + 1 for overlap check + cmpult r18, r16, r28 # true if src at lower addr than dest (note trans to self is not a "slow" case) + cmpult r16, r27, r27 # true if dst starts before end of src + beq r17, done # don't touch memory if length=0 + and r27, r28, r28 # does dst have bad overlap with src? + blbs r28, overlap # go handle poorly overlapping src/dst + + # simple forward loop case (~16 cycles/byte EV4) + # (length is presumed to be at least 1) + subq r18, 1, r18 # one before the beginning of the source + subq r16, 1, r16 # one before the beginning of the destination +forward_loop: + ldq_u r20, 1(r18) # load the qw containing the source + lda r18, 1(r18) # bump the source pointer + ldq_u r21, 1(r16) # load the qw containing the destination + lda r16, 1(r16) # bump the destination pointer + extbl r20 ,r18, r20 # get the byte to translate + addq r19, r20, r20 # get the address of the translation + ldq_u r27, (r20) # load the translation + subq r17, 1, r17 # decrement length + mskbl r21, r16, r21 # clear the bits in the destination + extbl r27, r20, r27 # extract the translation + insbl r27, r16, r27 # position for insertion + bis r27, r21, r21 # merge into the destination + stq_u r21, (r16) # store back + bgt r17, forward_loop # do another if there + +done: ret r31, (r26) + nop #.align 3 + + # bad overlap case (~16 cycles/byte EV4, 11c/byte EV5) + # (length is presumed to be at least 1) +overlap: + addq r17, r18, r18 # one past the end of the source + addq r17, r16, r16 # one past the end of the destination +backward_loop: + ldq_u r20, -1(r18) # load the qw containing the source + lda r18, -1(r18) # bump the source pointer + ldq_u r21, -1(r16) # load the qw containing the destination + lda r16, -1(r16) # bump the destination pointer + extbl r20 ,r18, r20 # get the byte to translate + addq r19, r20, r20 # get the address of the translation + ldq_u r27, (r20) # load the translation + subq r17, 1, r17 # decrement length + mskbl r21, r16, r21 # clear the bits in the destination + extbl r27, r20, r27 # extract the translation + insbl r27, r16, r27 # position for insertion + bis r27, r21, r21 # merge into the destination + stq_u r21, (r16) # store back + bgt r17, backward_loop # do another if there + + ret r31, (r26) + + .set at + .set reorder + .end _OtsStringTranslate diff --git a/private/crt32/misc/alpha/strcmp_.s b/private/crt32/misc/alpha/strcmp_.s new file mode 100644 index 000000000..dc25bfebc --- /dev/null +++ b/private/crt32/misc/alpha/strcmp_.s @@ -0,0 +1,357 @@ + #**************************************************************************** + #* * + #* Copyright (c) 1991 by * + #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. * + #* All rights reserved. * + #* * + #* This software is furnished under a license and may be used and copied * + #* only in accordance with the terms of such license and with the * + #* inclusion of the above copyright notice. This software or any other * + #* copies thereof may not be provided or otherwise made available to any * + #* other person. No title to and ownership of the software is hereby * + #* transferred. * + #* * + #* The information in this software is subject to change without notice * + #* and should not be construed as a commitment by Digital Equipment * + #* Corporation. * + #* * + #* Digital assumes no responsibility for the use or reliability of its * + #* software on equipment which is not supplied by Digital. * + #* * + #* * + #**************************************************************************** + # + #++ + # Facility: + # DEC C Run Time Library on the Alpha/WNT Platform + # + # Abstract: + # + # Implements the C RTL function strcmp() for the compiler intrinsic. + # + # Author: + # Bill Noyce 9-Aug-1991 + # + # Modified by: + # + # 001 Kevin Routley 10-Sep-1991 + # Modified to C RTL Coding standards. + # + # 002 Chris Bord 30 September 1991 + # Add decc$ prefixes. + # + # 003 Chris Bord 24 January 1992 + # Add second parameter to .procedure_descriptor directive + # + # 004 John Parks 22 January 1993 + # Ported to Alpha/NT. + #-- + +// +// Although the spec says the return value may be <0/0/>0, we now return +// -1/0/+1 to reduce NT combatibility problems. +// + + .globl _Otsstrcmp + .ent _Otsstrcmp + + # r16 = A + # r17 = B + # returns r0<0 if A<B, R0=0 if A=B, r0>0 if A>B (unsigned chars) + # destroys r16-r21, r27-r28 + # + +_Otsstrcmp: + .set noat + .set noreorder + + .frame $30, 0, $26 + + ldq_u $27, ($16) # Get first A QW + and $16, 7, $21 # Alignment of A + + ldq_u $18, ($17) # Get first B QW + and $17, 7, $20 # Alignment of B + + subq $20, $21, $0 # B_alignment geq A_alignment? + + cmpbge $31, $27, $19 # Any nulls in A? + + insql $27, $0, $28 # Position A like B if B_align geq + bgt $0, more_a # Skip if enough A bytes available + + srl $19, $21, $19 # Discard nulls preceding start of A + bne $0, more_b # Go handle opposite mismatch + +match: xor $27, $18, $28 # Do A and B differ? + + mskqh $28, $21, $28 # Ignore differences before start + + sll $19, $21, $0 # Line up nulls with differences + bne $19, null # Skip out if nulls seen + +loop_s: bne $28, diff # Skip out if difference seen + ldq_u $27, 8($16) # Get next A QW + + ldq_u $18, 8($17) # Get next B QW + addq $16, 8, $16 # Bump A pointer + + addq $17, 8, $17 # Bump B pointer + + cmpbge $31, $27, $0 # Any nulls in A? + + xor $27, $18, $28 # Do A and B differ? + beq $0, loop_s # Repeat if no nulls + + # Enter here if null seen. + # r0 = mask of nulls + # r27= A + # r18 = B + # r28= xor + # +null: subq $0, 1, $19 # Flip bits up thru first null + + cmpbge $31, $28, $28 # Mask of 1's where A=B + + xor $0, $19, $0 # Mask of 1's thru first null + + andnot $0, $28, $0 # Differences thru first null + + cmpbge $27, $18, $27 # Mask of 1's where A >= B + beq $0, done # Exit with R0=0 if no differences + + subq $31, $0, $19 # R19<0, first diff=1, others=0 + + and $27, $0, $28 # Mask of A>B thru first null + + and $28, $19, $0 # Keep only first difference + + cmoveq $0, $19, $0 # If A<B, set R0 negative + + cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0 + cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0 + subq $20, $21, $0 // set return value to -1/0/+1 + +done: ret $31, ($26) # All done + + # Enter here if difference seen, but no nulls. + # r27= A + # r18 = B + # R28= xor + # +diff: cmpbge $31, $28, $21 # Where is A = B? + + cmpbge $27, $18, $0 # Where is A >= B? + + subq $21, 255, $19 # R19<0, first diff=1, others=0 + + andnot $0, $21, $28 # Mask of A > B + + and $28, $19, $0 # Keep only first difference + + cmoveq $0, $19, $0 # If A<B, set R0 negative + + cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0 + cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0 + subq $20, $21, $0 // set return value to -1/0/+1 + + ret $31, ($26) + + #.align quad + + # Enter here if A and B alignments differ, and B's is greater (so there are + # more A bytes in its first QW than B bytes in its first QW). + +more_a: srl $19, $21, $19 # Discard nulls preceding start of A + + xor $28, $18, $21 # Do A and B differ? + + mskqh $21, $20, $21 # Discard diffs preceding start of B + bne $19, null_a # Skip if A has nulls + + mov $18, $19 # Put B where common code expects + + bne $21, diff_d # Handle diffs in B + + ldq_u $18, 8($17) # No nulls in A or B, get next QW of B + addq $17, 8, $17 # Bump B pointer + + insqh $27, $0, $28 # Position high part of A like B + + #stall + + mskql $18, $0, $19 # Keep low part of B + + # Loop comparing A and B when alignment differs. + # Register use: + # r16 --> A + # r17 --> B + # r27 = QW of A + # r28 = current piece of A + # r18 = QW of B + # r19 = current piece of B + # r0 = alignment difference (B-A) + # r21 = xor of pieces + # r20 = mask of null locations + # + # If a string contains a null, we are careful not to read the following + # quadword in that string. But we are willing to read the quadword that + # follows the first difference, because this read-ahead improves performance. + # +loop_d: xor $28, $19, $21 # Do A and B pieces differ? + ldq_u $27, 8($16) # Get next QW of A + + cmpbge $31, $18, $20 # Any nulls in B? + bne $21, diff_d # Skip if difference seen + +ent_d: mskqh $18, $0, $19 # Trim B for next compare + + insql $27, $0, $28 # Position A like B + + addq $16, 8, $16 # Bump A pointer + bne $20, null_d # Skip if null seen in B + + xor $28, $19, $21 # Do A and B pieces differ? + ldq_u $18, 8($17) # Get next QW of B + + cmpbge $31, $27, $20 # Any nulls in A? + bne $21, diff_d # Skip if difference seen + + insqh $27, $0, $28 # Position A for next compare + + mskql $18, $0, $19 # Trim B like A + + addq $17, 8, $17 # Bump B pointer + beq $20, loop_d # Repeat if no nulls in A + + # We saw a null in A. Since we've already compared the lower part with B, + # and B had no nulls, the null is in the upper part of A. We've moved that + # part of A to the lower part of r28. Re-compare so the mask of nulls will + # be positioned properly for the following code. + # + cmpbge $31, $28, $20 # Find nulls in repositioned A + + # Null seen and alignments differ. + # r28 = positioned A + # r19 = positioned B + # r20 = mask of nulls + # r21 = xor (at entry null_e) + # + #.odd +null_d: xor $28, $19, $21 # Where do A and B differ? + +null_e: subq $20, 1, $27 # Flip bits up thru first null + + cmpbge $31, $21, $18 # Mask of 1's where A=B + + xor $20, $27, $0 # Mask of 1's thru first null + + andnot $0, $18, $0 # Differences thru first null + + cmpbge $28, $19, $27 # Mask of 1's where A >= B + beq $0, done_d # Exit with R0=0 if no differences + + subq $31, $0, $19 # R19<0, first diff=1, others=0 + + and $27, $0, $0 # Mask of A>B thru first null + + and $0, $19, $0 # Keep only first difference + + cmoveq $0, $19, $0 # If A<B, set R0 negative + + cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0 + cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0 + subq $20, $21, $0 // set return value to -1/0/+1 + +done_d: ret $31, ($26) # All done + + + # Null seen in first QW of A, when B alignment greater. + # r19 = nulls in A, shifted + # r27 = A + # r28 = A positioned like B + # r18 = B + # r21 = xor, masked + # + #.odd +null_a: sll $19, $20, $20 # Position nulls like B + + mov $18, $19 # Move B for common code + bne $21, null_e # Comparison done if difference seen + + and $20, 255, $18 # Any nulls in first part of A? + + bne $18, null_e # Comparison done if so + + ldq_u $19, 8($17) # Get another B QW + insqh $27, $0, $28 # Position A to match + + srl $20, 8, $20 # Shift nulls again to match + br $31, null_d # Now we must be at end + + + # Enter here if A and B alignments differ, and B's is less (so there are more + # B bytes in its first QW than A bytes in its first QW). + + #.align quad +more_b: cmpbge $31, $18, $28 # We'll want to know about nulls in B + bne $19, null_b # Skip if null seen in A + + extqh $18, $0, $19 # Position B like A + + srl $28, $20, $28 # Discard nulls preceding start of B + + xor $27, $19, $27 # Do A and B differ? + + mskqh $27, $21, $21 # Discard diffs preceding start of A + + sll $28, $20, $20 # Position null mask for common code + ldq_u $27, 8($16) # Get next QW of A + + xor $19, $21, $28 # Recover A for compare + beq $21, ent_d # Enter loop if A=B so far + + + # Enter here if difference seen, but no nulls. + # r28 = A piece + # r19 = B piece + # r21 = xor + # +diff_d: cmpbge $31, $21, $21 # Where is A = B? + + cmpbge $28, $19, $0 # Where is A >= B? + + subq $21, 255, $27 # R27<0, first diff=1, others=0 + + andnot $0, $21, $0 # Mask of A > B + + and $0, $27, $0 # Keep only first difference + + cmoveq $0, $27, $0 # If A<B, set R0 negative + + cmplt $31, $0, $20 // set 1 if result > 0, otherwise 0 + cmplt $0, $31, $21 // set 1 if result < 0, otherwise 0 + subq $20, $21, $0 // set return value to -1/0/+1 + + ret $31, ($26) + + # Null seen in first QW of A, when B alignment less. + # r19 = nulls in A, shifted + # r27 = A + # r18 = original B + # + nop #.align 8 +null_b: sll $19, $21, $20 # Position null mask like A + + extqh $18, $0, $19 # Position B like A + + mov $27, $28 # Put A where common code expects + + xor $27, $19, $27 # Find differences + + mskqh $27, $21, $21 # Discard diffs preceding A + br $31, null_e # Comparison is done + + .set at + .set reorder + .end _Otsstrcmp diff --git a/private/crt32/misc/alpha/strcpy_.s b/private/crt32/misc/alpha/strcpy_.s new file mode 100644 index 000000000..de2057715 --- /dev/null +++ b/private/crt32/misc/alpha/strcpy_.s @@ -0,0 +1,257 @@ + #**************************************************************************** + #* * + #* Copyright (c) 1991 by * + #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. * + #* All rights reserved. * + #* * + #* This software is furnished under a license and may be used and copied * + #* only in accordance with the terms of such license and with the * + #* inclusion of the above copyright notice. This software or any other * + #* copies thereof may not be provided or otherwise made available to any * + #* other person. No title to and ownership of the software is hereby * + #* transferred. * + #* * + #* The information in this software is subject to change without notice * + #* and should not be construed as a commitment by Digital Equipment * + #* Corporation. * + #* * + #* Digital assumes no responsibility for the use or reliability of its * + #* software on equipment which is not supplied by Digital. * + #* * + #* * + #**************************************************************************** + # + #++ + # Facility: + # DEC C Run Time Library on the Alpha/WNT Platform + # + # Abstract: + # + # Implements the C RTL function strcpy() for the compiler intrinsic. + # + # Author: + # Bill Noyce 9-Aug-1991 + # + # Modified by: + # + # 001 Kevin Routley 10-Sep-1991 + # Modified to C RTL Coding standards. + # + # 002 Chris Bord 30 September 1991 + # Add decc$ prefixes. + # + # 003 Chris Bord 24 January 1992 + # Add second parameter to .procedure_descriptor directive + # + # 004 John Parks 22 January 1993 + # Ported to Alpha/NT. + #-- + + .globl _Otsstrcpy + .ent _Otsstrcpy + + # r16 = dst + # r17 = src + # returns r0 = src + # destroys r16-r21, r27-r28 + +_Otsstrcpy: + .set noat + .set noreorder + + ldq_u $27, ($17) # Get first src QW + and $16, 7, $28 #/ Is dst aligned? + lda $18, -1($31) # Get a mask of all 1's + bne $28, dst_unaligned #/ Go handle unaligned dst + and $17, 7, $19 # Is src aligned too? + nop + mov $16, $0 # Set up function result + bne $19, src_unaligned #/ Go handle aligned dst, unaligned src + +a_loop: + cmpbge $31, $27, $18 # Any nulls in src QW? + bne $18, a_exit_1 # Finish up if so + ldq $21, 8($17) # Load next QW if not +match: # Enter if src matches unaligned dst + addq $17, 16, $17 #/ Update src pointer for unrolled loop + stq_u $27, ($16) # Store a whole QW + addq $16, 16, $16 #/ Update dst pointer for unrolled loop + cmpbge $31, $21, $18 # Any nulls in src QW? + bne $18, a_exit_2 # Finish up if so + ldq $27, ($17) # Load next QW if not + stq_u $21, -8($16) # Store a whole QW + br $31, a_loop # Repeat during load latency + +a_exit_1: + ldq_u $21, ($16) # Get dst QW to update + subq $18, 1, $17 #/ Use location of null byte... + xor $18, $17, $18 # ... to compute mask of what to keep + zapnot $27, $18, $27 # Keep src up to & including null + zap $21, $18, $21 # Make room for new data + nop + or $21, $27, $21 # Combine src & dst... + stq_u $21, ($16) #/ ... and store + ret $31, ($26) + + nop +a_exit_2: + ldq_u $27, -8($16) # Get dst QW to update + subq $18, 1, $17 #/ Use location of null byte... + xor $18, $17, $18 # ... to compute mask of what to keep + zapnot $21, $18, $21 # Keep src up to & including null + zap $27, $18, $27 # Make room for new data + nop + or $27, $21, $27 # Combine src & dst... + stq_u $27, -8($16) #/ ... and store + ret $31, ($26) + +src_unaligned: # dst_unaligned code would work; is this faster? + mskqh $18, $17, $18 # Zeros where src to be ignored + ornot $27, $18, $19 # Make ignored bytes nonzero + cmpbge $31, $19, $21 # Any null bytes in src data? + extql $27, $17, $27 # Move src to position of dst + bne $21, short_ld #/ Finish up if nulls seen + ldq_u $19, 8($17) # Next src QW needed to fill dst + br $31, u_entry_2 # Enter loop for mismatched alignment + + # Here's the hard part. Enter with + # r16 = dst address + # r17 = src address + # r18 = -1 + # r27 = first src QW + # r28 = dst alignment (>0) + # Check whether the first src QW has any nulls, and load the next one. + # Combine these if needed to fill the first dst QW, and enter a loop + # that fetches src QWs and checks them, while storing dst QWs. + +dst_unaligned: + ldq_u $20, ($16) # Load dst to be updated + mskqh $18, $17, $18 #/ Zeros where src to be ignored + mov $16, $0 # Set up function result + ornot $27, $18, $19 # Make ignored bytes of src nonzero + cmpbge $31, $19, $21 # Any null bytes in src data? + extql $27, $17, $27 # Get only interesting src data + bne $21, short # Finish up if nulls seen + mskql $20, $16, $20 #/ Make room in dst + ldq_u $21, 8($17) # Load next src QW if no nulls + mskql $18, $16, $18 #/ Need two src QWs for first dst QW? + insql $27, $16, $27 # Move src data to position of dst + subq $17, $28, $17 # Adjust src ptr for partial move + and $17, 7, $28 # Is src now aligned? + bne $18, u_loop #/ Enter loop if one src QW fills dst + or $27, $20, $27 # Combine first src QW with dst + extqh $21, $17, $20 # Position 2nd src QW in 1st dst QW + cmpbge $31, $21, $18 # Any nulls in next src QW? + beq $28, match #/ If src aligned, use quick loop + mov $21, $19 # Put src QW where loop expects + bne $18, short_a #/ Finish up if nulls seen + + # r16 = address of next dst to store + # r17 = address-16 of next src to load + # r18 + # r19 = last loaded src QW + # r20 = one piece of dst QW + # r21 + # r27 = other piece of dst QW + # r28 + +u_loop: + ldq_u $28, 16($17) # Load another src QW + addq $17, 16, $17 #/ Update src pointer for unrolled loop + or $27, $20, $27 # Combine pieces + extql $19, $17, $20 # Get second part of prior src QW + stq_u $27, ($16) # Store a dst QW + cmpbge $31, $28, $19 #/ Any nulls in this src QW? + extqh $28, $17, $27 # Get first part of this src QW + bne $19, u_exit_2 #/ Finish up if nulls seen + ldq_u $19, 8($17) # Load another src QW + addq $16, 16, $16 #/ Update dst pointer for unrolled loop + or $27, $20, $20 # Combine pieces + extql $28, $17, $27 # Get second piece of prior src QW + stq_u $20, -8($16) # Store a dst QW +u_entry_2: + cmpbge $31, $19, $28 #/ Any nulls in this src QW? + extqh $19, $17, $20 # Get first part of this src QW + beq $28, u_loop #/ Repeat if no nulls seen + + subq $16, 8, $16 # Undo part of pointer update + mov $19, $28 # Move src QW to expected place +u_exit_2: + or $27, $20, $27 # Combine pieces + ldq_u $18, 8($16) #/ Load dst to update + cmpbge $31, $27, $21 # Is null in first dst QW? + bne $21, u_exit_3 # Skip if so + stq_u $27, 8($16) # Store a whole dst QW + extql $28, $17, $27 #/ Get second part of src QW + ldq_u $18, 16($16) # We'll update next dst QW + cmpbge $31, $27, $21 # Find location of null there + addq $16, 8, $16 # Update dst pointer +u_exit_3: + subq $21, 1, $28 # Using position of null byte... + xor $21, $28, $21 # ... make mask for desired src data + zapnot $27, $21, $27 # Trim src data after null + zap $18, $21, $18 # Make room for it in dst + nop + or $27, $18, $27 # Combine pieces + stq_u $27, 8($16) #/ Store dst QW + ret $31, ($26) +short_ld: + ldq_u $20, ($16) # Load dst QW to update +short: + cmpbge $31, $27, $17 #/ Get mask showing location of null + insql $27, $16, $18 # Move src data to position of dst + mskql $20, $16, $19 # Get dst bytes preceding string + sll $17, $28, $17 # Move mask in the same way + or $18, $19, $18 # Combine src & dst + and $17, 255, $28 # Null byte in first dst QW? + subq $17, 1, $19 # Using position of null byte... + xor $17, $19, $17 # ... make mask for desired src data + bne $28, short_2 #/ Skip if null in first dst QW + ldq_u $20, 8($16) # Load second dst QW + srl $17, 8, $17 #/ Move mask down for use + stq_u $18, ($16) # Store first dst QW + insqh $27, $16, $18 #/ Move src data to position of dst + addq $16, 8, $16 # Advance dst pointer +short_2: + zap $20, $17, $20 # Preserve dst data following null + zapnot $18, $17, $18 # Trim src data after null + nop + or $18, $20, $18 # Combine pieces + stq_u $18, ($16) #/ Store dst QW + ret $31, ($26) + + # r16 = dst address + # r17 = updated src address + # r18 = null position + # r19 = next src QW + # r20 = first part of r19, positioned for dst + # r21 + # r27 = dst QW so far + # r28 = low bits of updated src address + +short_a: + sll $18, 8, $18 # Shift location of null byte... + ldq_u $21, ($16) #/ Reload first dst QW + or $27, $20, $27 # Combine pieces + srl $18, $28, $18 # ... to position in dst QW's + nop + and $18, 255, $20 # Is null in first dst QW? + subq $18, 1, $28 # Using position of null byte... + xor $18, $28, $18 # ... make mask for desired src data + bne $20, short_a1 #/ Skip if null in first QW + stq_u $27, ($16) # Store a whole dst QW + extql $19, $17, $27 #/ Prepare next piece of src + ldq_u $21, 8($16) # Load second dst QW for update + srl $18, 8, $18 #/ Look at next 8 bits of mask + addq $16, 8, $16 # Update dst pointer +short_a1: + zapnot $27, $18, $27 # Keep src data + zap $21, $18, $21 # Keep end of dst QW + nop + or $27, $21, $27 # Combine pieces + stq_u $27, ($16) # Store last dst QW + ret $31, ($26) + + .set at + .set reorder + .end _Otsstrcpy diff --git a/private/crt32/misc/alpha/strlen_.s b/private/crt32/misc/alpha/strlen_.s new file mode 100644 index 000000000..2a7979387 --- /dev/null +++ b/private/crt32/misc/alpha/strlen_.s @@ -0,0 +1,95 @@ + #**************************************************************************** + #* * + #* Copyright (c) 1991 by * + #* DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts. * + #* All rights reserved. * + #* * + #* This software is furnished under a license and may be used and copied * + #* only in accordance with the terms of such license and with the * + #* inclusion of the above copyright notice. This software or any other * + #* copies thereof may not be provided or otherwise made available to any * + #* other person. No title to and ownership of the software is hereby * + #* transferred. * + #* * + #* The information in this software is subject to change without notice * + #* and should not be construed as a commitment by Digital Equipment * + #* Corporation. * + #* * + #* Digital assumes no responsibility for the use or reliability of its * + #* software on equipment which is not supplied by Digital. * + #* * + #* * + #**************************************************************************** + # + #++ + # Facility: + # DEC C Run Time Library on the Alpha/WNT Platform + # + # Abstract: + # + # Implements the C RTL function strlen() for the compiler intrinsic. + # + # Author: + # Bill Noyce 9-Aug-1991 + # + # Modified by: + # + # 001 Kevin Routley 10-Sep-1991 + # Modified to C RTL Coding standards. + # + # 002 Chris Bord 30 September 1991 + # + # 003 Chris Bord 24 January 1992 + # Add second parameter to .procedure_descriptor directive + # + # 004 John Parks 22 January 1993 + # Ported to Alpha/NT. + #-- + + .globl _Otsstrlen + .ent _Otsstrlen + + # r16 = src pointer + # Returns r0 = length + # Destroys r16,r27-r28 + +_Otsstrlen: + .set noat + .set noreorder + + ldq_u $27, ($16) # Get QW containing start of string + lda $28, -1($31) # Mask of all ones + mskql $28, $16, $28 # Nonzeros in low bytes to be ignored + and $16, 7, $0 # Alignment = bytes not to be counted + or $27, $28, $27 # Fill ignored bytes with nonzeros + cmpbge $31, $27, $27 # Any null bytes in this QW? + subq $31, $0, $0 # Initialize count to -alignment + bne $27, bottom # Skip if null byte seen + +loop: ldq_u $27, 8($16) # Load next QW of string + addq $16, 8, $16 # Advance pointer + addq $0, 8, $0 # Increment length + cmpbge $31, $27, $27 # Any nulls in this QW? + beq $27, loop # Repeat if not + +bottom: and $27, 0xF, $28 # Null in low longword? + subq $27, 1, $16 # Complement the lowest 1-bit in mask + blbs $27, done # Exit if null appears in first byte + andnot $27, $16, $27 # Make single-bit mask of null location + beq $28, geq_4 # Skip if null is in high longword + srl $27, 2, $27 # Map 2/4/8 --> 0/1/2 + addq $0, 1, $0 # Bump length by one... + addq $0, $27, $0 # ... and then by null location + +done: ret $31, ($26) + +geq_4: srl $27, 5, $28 # Map 10/20/40/80 --> 0/1/2/4 + srl $27, 7, $27 # Map 10/20/40/80 --> 0/0/0/1 + addq $0, 4, $0 # Bump length by four + subq $28, $27, $28 # Compute location within high LW... + addq $0, $28, $0 # ... and add to length + ret $31, ($26) + + .set at + .set reorder + .end _Otsstrlen diff --git a/private/crt32/misc/alpha/szero.s b/private/crt32/misc/alpha/szero.s new file mode 100644 index 000000000..c97c31df5 --- /dev/null +++ b/private/crt32/misc/alpha/szero.s @@ -0,0 +1,137 @@ + #++ + # Copyright 1991, 1994, Digital Equipment Corporation + # + # ots_zero(char *dstptr, long dstlen) + # + # Zero dstlen bytes of memory at *dstptr + # + # Special conventions: No stack space, r16-r17 and r27-r28 ONLY, + # no linkage pointer required. + # (Warning: The auto-loader potentially takes some regs across + # the call if this is being used in a shared lib. environment.) + # + # This is a GEM support routine for zeroing a region of memory. It is + # basically idential to BSD's bzero, though it has limited register + # convensions to allow it to work better with compiled code. (Note that + # this is just a stripped down version of ots_fill.) + # + # This is optimized for extremely high performance both for small and + # large blocks. In order to reduce overhead for small cases, they are + # retired as quickly as possible, more case analysis is reserved + # for cases which will do more. + # + # This version of OTS_ZERO provides longword granularity for Alpha. + # + # 012 30 Aug 1994 WBN Longword granularity version based on + # OTS_ZERO_ALPHA.M64 edit 011. + #-- + +#include "ots_defs.hs" + + # r16 = dst + # r17 = len + # destroys r16-r17, r27-r28 + + .globl _OtsZero + .ent _OtsZero +_OtsZero: + .set noat + .set noreorder + .frame sp,0,r26 + .prologue 0 + beq r17, done # No memory refs if len=0 + subq r17, 4, r28 # Length-4 + and r16, 3, r27 # Dst alignment (0-3) + andnot r16, 3, r16 # LW aligned dst pointer + addq r27, r28, r17 # Alignment + length - 4 + bge r28, geq4 # Lengths >= 4 may not need load + ldl r28, (r16) # Load first LW of dst + bgt r17, double # Skip if it crosses to next LW + addq r17, 4, r17 # Find endpoint within LW + mskql r28, r27, r27 # Clear from startpoint thru 7 + mskqh r28, r17, r28 # Clear from 0 to endpoint + or r28, r27, r27 # Combine dest parts + stl r27, (r16) + ret r31, (r26) + +double: mskql r28, r27, r28 # Clear from startpoint in first LW + ldl r27, 4(r16) # Load second LW of dst + stl r28, (r16) + mskqh r27, r17, r27 # Clear up to endpoint in second LW + stl r27, 4(r16) + ret r31, (r26) + + # Come here if length to be zeroed is >= 4. + # r16-> dst aligned to LW + # r17 = alignment + length - 4 + # r27 = dst alignment within LW + # r28 = length-4 + + #.align quad + +geq4: and r16, 4, r28 # Which LW in QW to store first? + beq r17, simple # Go handle single aligned LW + bne r28, longs # Go use QW stores +quad: subq r17, 4, r17 # Does dest end in first QW? + blt r17, shortq # Ends within first QW + beq r27, wh_qw # Store a whole QW + ldq r28, (r16) # Load first QW of dest + mskql r28, r27, r27 # Clear from startpoint +wh_qw: stq r27, (r16) # Store first QW of dest + br r31, join # Go clear rest of string + +simple: stl r31, (r16) # Single aligned LW + ret r31, (r26) + +shortq: ldq r28, (r16) # Load QW of dest + mskql r28, r27, r27 # Clear from startpoint thru 7 + mskqh r28, r17, r28 # Clear from 0 up to endpoint + or r28, r27, r27 # Merge + stq r27, (r16) # Store + ret r31, (r26) + +longs: beq r27, wh_lw # Store a whole LW + ldl r28, (r16) # Load first LW of dest + mskql r28, r27, r27 # Clear from startpoint +wh_lw: stl r27, (r16) # Store first LW of dest +join: subq r17, 32, r17 # At least 4 more quadwords? + and r17, 24, r27 # How many after multiple of 4? + bge r17, unroll # Taken branch for long strings +short: and r17, 7, r17 # How many odd bytes? + beq r27, last # Skip if no more whole QWs + stq_u r31, 8(r16) # Clear one... + subq r27, 16, r27 # Map 8/16/24 to -8/0/8 + addq r16, 8, r16 # Update dest pointer + blt r27, last # Skip if no more whole QWs + #stall + stq_u r31, 8(r16) # Clear two... + addq r16, 8, r16 # Update dest pointer + nop + beq r27, last # Skip if no more whole QWs + stq_u r31, 8(r16) # Clear three... + addq r16, 8, r16 # Update dest pointer +last: beq r17, done # Finished if no odd bytes + ldq_u r27, 8(r16) # Load last QW of dst + subq r17, 4, r28 # More than a LW left? + andnot r16, 7, r16 # Clean pointer for STL + mskqh r27, r17, r27 # Clear up to endpoint + bgt r28, lastq # Go store a QW + stl r27, 8(r16) # LW store for last piece +done: ret r31, (r26) + +lastq: stq r27, 8(r16) # QW store for last piece + ret r31, (r26) + +unroll: stq_u r31, 8(r16) # Store 4 QWs per iteration + stq_u r31, 16(r16) + stq_u r31, 24(r16) + subq r17, 32, r17 # Decrement remaining count + stq_u r31, 32(r16) + addq r16, 32, r16 # Update dest pointer + bge r17, unroll # Repeat until done + br r31, short # Then handle leftovers + + + .set at + .set reorder + .end _OtsZero diff --git a/private/crt32/misc/assert.c b/private/crt32/misc/assert.c new file mode 100644 index 000000000..7f7dc60a0 --- /dev/null +++ b/private/crt32/misc/assert.c @@ -0,0 +1,66 @@ +/*** +*assert.c - Display a message and abort +* +* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* +*Revision History: +* 05-19-88 JCR Module created. +* 08-10-88 PHG Corrected copyright date +* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include +* <cruntime.h>. Also, fixed the copyright. +* 04-05-90 GJF Added #include <assert.h> +* 10-04-90 GJF New-style function declarator. +* 06-19-91 GJF Conditionally use setvbuf() on stderr to prevent +* the implicit call to malloc() if stderr is being used +* for the first time (assert() should work even if the +* heap is trashed). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <file2.h> +#include <stdlib.h> +#include <stdio.h> + +#undef NDEBUG +#include <assert.h> + +static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n"; + +/*** +*_assert() - Display a message and abort +* +*Purpose: +* The assert macro calls this routine if the assert expression is +* true. By placing the assert code in a subroutine instead of within +* the body of the macro, programs that call assert multiple times will +* save space. +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _assert ( + void *expr, + void *filename, + unsigned lineno + ) +{ + if ( !anybuf(stderr) ) + /* + * stderr is unused, hence unbuffered, as yet. set it to + * single character buffering (to avoid a malloc() of a + * stream buffer). + */ + (void) setvbuf(stderr, NULL, _IONBF, 0); + + fprintf(stderr, _assertstring, expr, filename, lineno); + fflush(stderr); + abort(); +} diff --git a/private/crt32/misc/bsearch.c b/private/crt32/misc/bsearch.c new file mode 100644 index 000000000..5769de6b5 --- /dev/null +++ b/private/crt32/misc/bsearch.c @@ -0,0 +1,99 @@ +/*** +*bsearch.c - do a binary search +* +* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines bsearch() - do a binary search an an array +* +*Revision History: +* 07-05-84 RN initial version +* 06-19-85 TC put in ifdefs to handle case of multiplication +* in large/huge model. +* 04-13-87 JCR added const to declaration +* 08-04-87 JCR Added "long" cast to mid= assignment for large/huge +* model. +* 11-10-87 SKS Removed IBMC20 switch +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-21-88 JCR Backed out _LOAD_DS... +* 02-22-88 JCR Added cast to get rid of cl const warning +* 10-20-89 JCR Added _cdecl to prototype, changed 'char' to 'void' +* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and fixed +* the copyright. Also, cleaned up the formatting a bit. +* 04-05-90 GJF Added #include <stdlib.h> and #include <search.h>. +* Fixed some resulting compiler warnings (at -W3). +* Also, removed #include <sizeptr.h>. +* 07-25-90 SBM Removed redundant include (stdio.h), made args match +* prototype +* 10-04-90 GJF New-style function declarator. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <search.h> + +/*** +*char *bsearch() - do a binary search on an array +* +*Purpose: +* Does a binary search of a sorted array for a key. +* +*Entry: +* const char *key - key to search for +* const char *base - base of sorted array to search +* unsigned int num - number of elements in array +* unsigned int width - number of bytes per element +* int (*compare)() - pointer to function that compares two array +* elements, returning neg when #1 < #2, pos when #1 > #2, and +* 0 when they are equal. Function is passed pointers to two +* array elements. +* +*Exit: +* if key is found: +* returns pointer to occurrence of key in array +* if key is not found: +* returns NULL +* +*Exceptions: +* +*******************************************************************************/ + +void * _CALLTYPE1 bsearch ( + REG4 const void *key, + const void *base, + size_t num, + size_t width, + int (_CALLTYPE1 *compare)(const void *, const void *) + ) +{ + REG1 char *lo = (char *)base; + REG2 char *hi = (char *)base + (num - 1) * width; + REG3 char *mid; + unsigned int half; + int result; + + while (lo <= hi) + if (half = num / 2) + { + mid = lo + (num & 1 ? half : (half - 1)) * width; + if (!(result = (*compare)(key,mid))) + return(mid); + else if (result < 0) + { + hi = mid - width; + num = num & 1 ? half : half-1; + } + else { + lo = mid + width; + num = half; + } + } + else if (num) + return((*compare)(key,lo) ? NULL : lo); + else + break; + + return(NULL); +} diff --git a/private/crt32/misc/cmiscdat.c b/private/crt32/misc/cmiscdat.c new file mode 100644 index 000000000..d1458d8f9 --- /dev/null +++ b/private/crt32/misc/cmiscdat.c @@ -0,0 +1,68 @@ +/*** +*cmiscdat.c - miscellaneous C run-time data +* +* Copyright (c) 1989-1990, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Includes floating point conversion table (for C float output), +* a data structure used by signal/exec to tell if a SIGINT handler +* has been installed, and the public variables _asizeC and _asizeD +* for conveying memory-model information to the memory-model-independent +* GRAPHICS.LIB. +* +* When floating point i/o conversions are done, but no floating-point +* variables or expressions are used in the C program, we use the +* _cfltcvt_tab[] to map these cases to the _fptrap entry point, +* which prints "floating point not loaded" and dies. +* +* This table is initialized to six copies of _fptrap by default. +* If floating-point is linked in (_fltused), these table entries +* are reset (see input.c, output.c, fltused.asm, and fltuseda.asm). +* +*Revision History: +* 06-29-89 PHG module created, based on asm version +* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright +* and cleaned up the formatting a bit. +* 07-31-90 SBM Updated comments slightly +* 08-29-90 SBM Added #include <internal.h> and <fltintrn.h>, +* removed _fptrap() prototype +* +*******************************************************************************/ + +#include <cruntime.h> +#include <internal.h> +#include <fltintrn.h> + +/* + ... table of (model-dependent) code pointers ... + + Six entries, all point to _fptrap by default, + but are changed to point to the appropriate + routine if the _fltused initializer (_cfltcvt_init) + is linked in. + + this table is used or modified in the following + source files: + + \clib\stdio\input.c + \clib\stdio\output.c + \math\c\fltused.asm + \math\c\fltuseda.asm + + if the _fltused modules are linked in, then the + _cfltcvt_init initializer sets the 6 entries of + _cfltcvt_tab to: + + _cfltcvt + _cropzeros + _fassign + _forcdecpt + _positive + _cldcvt +*/ + +void (*_cfltcvt_tab[6])(void) = { + _fptrap, _fptrap, _fptrap, _fptrap, _fptrap, _fptrap +}; + +void (*_sigintoff)() = 0; /* SIGINT default signal routine */ diff --git a/private/crt32/misc/ctype.c b/private/crt32/misc/ctype.c new file mode 100644 index 000000000..382779c6d --- /dev/null +++ b/private/crt32/misc/ctype.c @@ -0,0 +1,161 @@ +/*** +*ctype.c - _ctype definition file +* +* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* _ctype definition file of character classification data. This file +* initializes the array used by the character classification macros +* in ctype.h. +* +*Revision History: +* 06-08-89 PHG Module created, based on asm version +* 08-28-89 JCR Corrected _ctype declaration to match ctype.h +* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright. +* 10-08-91 ETC _ctype table is unsigned short under _INTL. +* 11-11-91 ETC Declare _pctype and _pwctype under _INTL. +* 12-16-91 ETC Make ctype table width independent of _INTL, use +* _NEWCTYPETABLE for short table, else char. +* 04-06-92 KRS Remove _INTL switches. +* 01-19-03 CFW Move to _NEWCTYPETABLE, remove switch. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <ctype.h> + +unsigned short *_pctype = _ctype+1; /* pointer to table for char's */ +unsigned short *_pwctype = _ctype+1; /* pointer to table for wchar_t's */ + +unsigned short _VARTYPE1 _ctype[257] = { + 0, /* -1 EOF */ + _CONTROL, /* 00 (NUL) */ + _CONTROL, /* 01 (SOH) */ + _CONTROL, /* 02 (STX) */ + _CONTROL, /* 03 (ETX) */ + _CONTROL, /* 04 (EOT) */ + _CONTROL, /* 05 (ENQ) */ + _CONTROL, /* 06 (ACK) */ + _CONTROL, /* 07 (BEL) */ + _CONTROL, /* 08 (BS) */ + _SPACE+_CONTROL, /* 09 (HT) */ + _SPACE+_CONTROL, /* 0A (LF) */ + _SPACE+_CONTROL, /* 0B (VT) */ + _SPACE+_CONTROL, /* 0C (FF) */ + _SPACE+_CONTROL, /* 0D (CR) */ + _CONTROL, /* 0E (SI) */ + _CONTROL, /* 0F (SO) */ + _CONTROL, /* 10 (DLE) */ + _CONTROL, /* 11 (DC1) */ + _CONTROL, /* 12 (DC2) */ + _CONTROL, /* 13 (DC3) */ + _CONTROL, /* 14 (DC4) */ + _CONTROL, /* 15 (NAK) */ + _CONTROL, /* 16 (SYN) */ + _CONTROL, /* 17 (ETB) */ + _CONTROL, /* 18 (CAN) */ + _CONTROL, /* 19 (EM) */ + _CONTROL, /* 1A (SUB) */ + _CONTROL, /* 1B (ESC) */ + _CONTROL, /* 1C (FS) */ + _CONTROL, /* 1D (GS) */ + _CONTROL, /* 1E (RS) */ + _CONTROL, /* 1F (US) */ + _SPACE+_BLANK, /* 20 SPACE */ + _PUNCT, /* 21 ! */ + _PUNCT, /* 22 " */ + _PUNCT, /* 23 # */ + _PUNCT, /* 24 $ */ + _PUNCT, /* 25 % */ + _PUNCT, /* 26 & */ + _PUNCT, /* 27 ' */ + _PUNCT, /* 28 ( */ + _PUNCT, /* 29 ) */ + _PUNCT, /* 2A * */ + _PUNCT, /* 2B + */ + _PUNCT, /* 2C , */ + _PUNCT, /* 2D - */ + _PUNCT, /* 2E . */ + _PUNCT, /* 2F / */ + _DIGIT+_HEX, /* 30 0 */ + _DIGIT+_HEX, /* 31 1 */ + _DIGIT+_HEX, /* 32 2 */ + _DIGIT+_HEX, /* 33 3 */ + _DIGIT+_HEX, /* 34 4 */ + _DIGIT+_HEX, /* 35 5 */ + _DIGIT+_HEX, /* 36 6 */ + _DIGIT+_HEX, /* 37 7 */ + _DIGIT+_HEX, /* 38 8 */ + _DIGIT+_HEX, /* 39 9 */ + _PUNCT, /* 3A : */ + _PUNCT, /* 3B ; */ + _PUNCT, /* 3C < */ + _PUNCT, /* 3D = */ + _PUNCT, /* 3E > */ + _PUNCT, /* 3F ? */ + _PUNCT, /* 40 @ */ + _UPPER+_HEX, /* 41 A */ + _UPPER+_HEX, /* 42 B */ + _UPPER+_HEX, /* 43 C */ + _UPPER+_HEX, /* 44 D */ + _UPPER+_HEX, /* 45 E */ + _UPPER+_HEX, /* 46 F */ + _UPPER, /* 47 G */ + _UPPER, /* 48 H */ + _UPPER, /* 49 I */ + _UPPER, /* 4A J */ + _UPPER, /* 4B K */ + _UPPER, /* 4C L */ + _UPPER, /* 4D M */ + _UPPER, /* 4E N */ + _UPPER, /* 4F O */ + _UPPER, /* 50 P */ + _UPPER, /* 51 Q */ + _UPPER, /* 52 R */ + _UPPER, /* 53 S */ + _UPPER, /* 54 T */ + _UPPER, /* 55 U */ + _UPPER, /* 56 V */ + _UPPER, /* 57 W */ + _UPPER, /* 58 X */ + _UPPER, /* 59 Y */ + _UPPER, /* 5A Z */ + _PUNCT, /* 5B [ */ + _PUNCT, /* 5C \ */ + _PUNCT, /* 5D ] */ + _PUNCT, /* 5E ^ */ + _PUNCT, /* 5F _ */ + _PUNCT, /* 60 ` */ + _LOWER+_HEX, /* 61 a */ + _LOWER+_HEX, /* 62 b */ + _LOWER+_HEX, /* 63 c */ + _LOWER+_HEX, /* 64 d */ + _LOWER+_HEX, /* 65 e */ + _LOWER+_HEX, /* 66 f */ + _LOWER, /* 67 g */ + _LOWER, /* 68 h */ + _LOWER, /* 69 i */ + _LOWER, /* 6A j */ + _LOWER, /* 6B k */ + _LOWER, /* 6C l */ + _LOWER, /* 6D m */ + _LOWER, /* 6E n */ + _LOWER, /* 6F o */ + _LOWER, /* 70 p */ + _LOWER, /* 71 q */ + _LOWER, /* 72 r */ + _LOWER, /* 73 s */ + _LOWER, /* 74 t */ + _LOWER, /* 75 u */ + _LOWER, /* 76 v */ + _LOWER, /* 77 w */ + _LOWER, /* 78 x */ + _LOWER, /* 79 y */ + _LOWER, /* 7A z */ + _PUNCT, /* 7B { */ + _PUNCT, /* 7C | */ + _PUNCT, /* 7D } */ + _PUNCT, /* 7E ~ */ + _CONTROL, /* 7F (DEL) */ + /* and the rest are 0... */ +}; diff --git a/private/crt32/misc/div.c b/private/crt32/misc/div.c new file mode 100644 index 000000000..de8cfa3ec --- /dev/null +++ b/private/crt32/misc/div.c @@ -0,0 +1,59 @@ +/*** +*div.c - contains the div routine +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Performs a signed divide and returns quotient +* and remainder. +* +*Revision History: +* 06-02-89 PHG module created +* 03-14-90 GJF Made calling type _CALLTYPE1 and added #include +* <cruntime.h>. Also, fixed the copyright. +* 10-04-90 GJF New-style function declarator. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> + +/*** +*div_t div(int numer, int denom) - do signed divide +* +*Purpose: +* This routine does an divide and returns the results. +* Since we don't know how the Intel 860 does division, we'd +* better make sure that we have done it right. +* +*Entry: +* int numer - Numerator passed in on stack +* int denom - Denominator passed in on stack +* +*Exit: +* returns quotient and remainder in structure +* +*Exceptions: +* No validation is done on [denom]* thus, if [denom] is 0, +* this routine will trap. +* +*******************************************************************************/ + +div_t _CALLTYPE1 div ( + int numer, + int denom + ) +{ + div_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + /* did division wrong; must fix up */ + ++result.quot; + result.rem -= denom; + } + + return result; +} diff --git a/private/crt32/misc/getenv.c b/private/crt32/misc/getenv.c new file mode 100644 index 000000000..7d14d2a74 --- /dev/null +++ b/private/crt32/misc/getenv.c @@ -0,0 +1,167 @@ +/*** +*getenv.c - get the value of an environment variable +* +* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines getenv() - searches the environment for a string variable +* and returns the value of it. +* +*Revision History: +* 11-22-83 RN initial version +* 04-13-87 JCR added const to declaration +* 11-09-87 SKS avoid indexing past end of strings (add strlen check) +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 06-01-88 PHG Merged normal/DLL versions +* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and fixed +* the copyright. Also, cleaned up the formatting a bit. +* 04-05-90 GJF Added #include <string.h>. +* 07-25-90 SBM Removed redundant include (stdio.h) +* 08-13-90 SBM Compiles cleanly with -W3 (made length unsigned int) +* 10-04-90 GJF New-style function declarator. +* 01-18-91 GJF ANSI naming. +* 02-06-91 SRW Added _WIN32_ conditional for GetEnvironmentVariable +* 02-18-91 SRW Removed _WIN32_ conditional for GetEnvironmentVariable +* 01-10-92 GJF Final unlock and return statements shouldn't be in +* if-block. +* 03-11-92 GJF Use case-insensitive comparison for Win32. +* 04-27-92 GJF Repackaged MTHREAD support for Win32 to create a +* _getenv_lk. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <string.h> +#include <os2dll.h> +#include <oscalls.h> + +/*** +*char *getenv(option) - search environment for a string +* +*Purpose: +* searches the environment for a string of the form "option=value", +* if found, return value, otherwise NULL. +* +*Entry: +* const char *option - variable to search for in environment +* +*Exit: +* returns the value part of the environment string if found, +* otherwise NULL +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef _CRUISER_ + +char * _CALLTYPE1 getenv ( + REG3 const char *option + ) +{ +#ifdef _POSIX_ + REG1 char **search = environ; +#else + REG1 char **search = _environ; +#endif + REG2 unsigned int length; + + _mlock( _ENV_LOCK ); + + if (search && option) + { + + length = strlen(option); + + /* + ** Make sure `*search' is long enough to be a candidate + ** (We must NOT index past the '\0' at the end of `*search'!) + ** and that it has an equal sign (`=') in the correct spot. + ** If both of these requirements are met, compare the strings. + */ + while (*search) + { + if (strlen(*search) > length && (*(*search + length) + == '=') && (strncmp(*search, option, length) == 0)) { + _munlock( _ENV_LOCK ); + return(*search + length + 1); + } + + search++; + } + } + + _munlock( _ENV_LOCK ); + return(NULL); +} + + +#else /* ndef _CRUISER_ */ +#ifdef _WIN32_ + + +#ifdef MTHREAD + + +char * _CALLTYPE1 getenv ( + const char *option + ) +{ + char *retval; + + _mlock(_ENV_LOCK); + + retval = _getenv_lk(option); + + _munlock(_ENV_LOCK); + + return(retval); + +} + + +char * _CALLTYPE1 _getenv_lk ( + const char *option + ) + +#else /* ndef MTHREAD */ + +char * _CALLTYPE1 getenv ( + const char *option + ) + +#endif /* MTHREAD */ +{ + char **search = _environ; + unsigned int length; + + if (search && option) + { + + length = strlen(option); + + /* + ** Make sure `*search' is long enough to be a candidate + ** (We must NOT index past the '\0' at the end of `*search'!) + ** and that it has an equal sign (`=') in the correct spot. + ** If both of these requirements are met, compare the strings. + */ + while (*search) + { + if (strlen(*search) > length && (*(*search + length) + == '=') && (strnicmp(*search, option, length) == 0)) { + return(*search + length + 1); + } + + search++; + } + } + + return(NULL); +} + + +#endif /* _WIN32_ */ +#endif /* _CRUISER_ */ diff --git a/private/crt32/misc/getpath.c b/private/crt32/misc/getpath.c new file mode 100644 index 000000000..96782f176 --- /dev/null +++ b/private/crt32/misc/getpath.c @@ -0,0 +1,174 @@ +/*** +*getpath.c - extract a pathname from an environment variable +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Extract pathnames from a string of semicolon delimited pathnames +* (generally the value of an environment variable such as PATH). +* +*Revision History: +* 08-25-89 GJF Module created (taken from SEARCHEN.C and revised) +* 03-14-90 GJF Replaced near with _CALLTYPE1 and added #include +* <cruntime.h> +* 07-25-90 SBM Replaced <stdio.h> by <stddef.h> +* 10-04-90 GJF New-style function declarator. +* 04-26-91 SRW Removed level 3 warnings +* 09-18-91 JCR Strip off leading semi-colons (bug fix) +* 09-25-91 JCR Changed ifdef "OS2" to "_HPFS_" and defined it +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stddef.h> +#include <internal.h> + +/* support HPFS file system */ +#define _HPFS_ 1 + +/*** +*_getpath() - extract a pathname from a semicolon-delimited list of pathnames +* +*Purpose: +* To extract the next pathname from a semicolon-delimited list of +* pathnames (usually the value on an environment variable) and copy +* it to a caller-specified buffer. No check is done to see if the path +* is valid. The maximum number of characters copied to the buffer is +* maxlen - 1 (and then a '\0' is appended). +* +#ifdef _HPFS_ +* If we hit a quoted string, then allow any characters inside. +* For example, to put a semi-colon in a path, the user could have +* an environment variable that looks like: +* +* PATH=C:\BIN;"D:\CRT\TOOLS;B1";C:\BINP +#endif +* +* NOTE: Semi-colons in sequence are skipped over; pointers to 0-length +* pathnames are NOT returned (this includes leading semi-colons). +* +* NOTE: If this routine is made user-callable, the near attribute +* must be replaced by _LOAD_DS and the prototype moved from INTERNAL.H +* to STDLIB.H. The source files MISC\SEARCHEN.C and EXEC\SPAWNVPE.C +* will need to be recompiled, but should not require any changes. +* +*Entry: +* src - Pointer to a string of 0 or more path specificiations, +* delimited by semicolons (';'), and terminated by a null +* character +* dst - Pointer to the buffer where the next path specification is to +* be copied +* maxlen - Maximum number of characters to be copied, counting the +* terminating null character. Note that a value of 0 is treated +* as UINT_MAX + 1. +* +*Exit: +* If a pathname is successfully extracted and copied, a pointer to the +* first character of next pathname is returned (intervening semicolons +* are skipped over). If the pathname is too long, as much as possible +* is copied to the user-specified buffer and NULL is returned. +* +* Note that the no check is made of the validity of the copied pathname. +* +*Exceptions: +* +*******************************************************************************/ + +char * _CALLTYPE1 _getpath ( + register const char *src, + register char *dst, + unsigned maxlen + ) +{ + const char *save_src; + + /* + * strip off leading semi colons + */ + while ( *src == ';' ) + src++; + + /* + * Save original src pointer + */ + save_src = src; + + /* + * Decrement maxlen to allow for the terminating '\0' + */ + if ( --maxlen == 0 ) + goto appendnull; + + + /* + * Get the next path in src string + */ + while (*src && (*src != ';')) { + +#ifdef _HPFS_ + + /* + * Check for quote char + */ + if (*src != '"') { + + *dst++ = *src++; + + if ( --maxlen == 0 ) { + save_src = src; /* ensure NULL return */ + goto appendnull; + } + + } + else { + + /* + * Found a quote. Copy all chars until we hit the + * final quote or the end of the string. + */ + src++; /* skip over opening quote */ + + while (*src && (*src != '"')) { + + *dst++ = *src++; + + if ( --maxlen == 0 ) { + save_src = src; /* ensure NULL return */ + goto appendnull; + } + } + + if (*src) + src++; /* skip over closing quote */ + + } + +#else + + *dst++ = *src++; + + if ( --maxlen == 0 ) { + save_src = src; /* ensure NULL return */ + goto appendnull; + } + +#endif + + } + + /* + * If we copied something and stopped because of a ';', + * skip the ';' before returning + */ + while ( *src == ';' ) + src++; + + /* + * Store a terminating null + */ +appendnull: + + *dst = '\0'; + + return((save_src != src) ? (char *)src : NULL); +} diff --git a/private/crt32/misc/getqloc.c b/private/crt32/misc/getqloc.c new file mode 100644 index 000000000..b9ab3461f --- /dev/null +++ b/private/crt32/misc/getqloc.c @@ -0,0 +1,736 @@ +/*** +*getqloc.c - get qualified locale +* +* Copyright (c) 1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _get_qualified_locale - get complete locale information +* +* NOTE: this should be a one-line call to an NT routine, but since NT does +* not currently support the needed functionality, this will suffice, +* it MUST be changed when NT supports changes. +* +* STAGE 1: convert input to internal LC_ID +* +* STAGE 2: qualify internal LC_ID +* Locales in NT version 1 are really just a language and a sublanguage; +* the language info is not useful. We therefore do not return a true +* country code, but rather return the language for that country. +* +* STAGE 3: convert to proper output format +* If output is an Id, no conversion necessary. If output is a string, call +* NT routines to get English strings for qualified locale. +** +*Revision History: +* 12-11-92 CFW initial version +* 01-08-93 CFW cleaned up file +* 02-02-93 CFW Added test for NULL input string fields +* 02-08-93 CFW Casts to remove warnings. +* 02-18-93 CFW Removed debugging support routines, changed copyright. +* 02-18-93 CFW Removed debugging support routines, changed copyright. +* 03-01-93 CFW Test code page validity, use ANSI comments. +* 03-02-93 CFW Add ISO 3166 3-letter country codes, verify country table. +* 03-04-93 CFW Call IsValidCodePage to test code page vailidity. +* 03-10-93 CFW Protect table testing code. +* 03-17-93 CFW Add __ to lang & ctry info tables, move defs to setlocal.h. +* 03-23-93 CFW Make internal functions static, add _ to GetQualifiedLocale. +* 03-24-93 CFW Change to _get_qualified_locale, support ".codepage". +* 04-20-93 CFW Enable all strange countries. +* 05-20-93 GJF Include windows.h, not individual win*.h files +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <string.h> +#include <windows.h> +#include <setlocal.h> + +#define iAslpStr(i) ((LPLC_STRINGS)i) +#define iAslpId(i) ((LPLC_ID)i) + +#define MAX_TEMP_STR_LEN (max(MAX_LANG_LEN, max(MAX_CTRY_LEN, MAX_CP_LEN))) + +static WORD trans_lang_lang(const PSZ pszLang); +static WORD trans_ctry_ctry(const PSZ pszCtry); +static WORD trans_ctry_lang(WORD wCtry); +static BOOL match_ctry_lang(WORD *pwCtry, WORD *pwLang); +static VOID pszcpywcs(PSZ pszStr, PWSTR pwStr); + +/* Languages supported are according to "Win32 NLSAPI Functional */ +/* Specification" of 15 September, 1992 */ + +#define LANG_STR_NUM 92 /* number of language strings + 1 for algorithm */ + +LANGREC __rg_lang_rec[] = +{ + {"", MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)}, + {"american", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"american english", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"american-english", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"australian", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)}, + {"belgian", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)}, + {"canadian", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)}, + {"chinese", MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT)}, + {"chinese-simplified", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)}, + {"chinese-traditional", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)}, + {"chs", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)}, + {"cht", MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)}, + {"csy", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)}, + {"czech", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)}, + {"dan", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)}, + {"danish", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)}, + {"dea", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN)}, + {"des", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)}, + {"deu", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)}, + {"dutch", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)}, + {"dutch-belgian", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)}, + {"ell", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)}, + {"ena", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)}, + {"enc", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)}, + {"eng", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)}, + {"english", MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)}, + {"english-american", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"english-aus", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS)}, + {"english-can", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN)}, + {"english-nz", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_NZ)}, + {"english-uk", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)}, + {"english-us", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"english-usa", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"enu", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"enz", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_NZ)}, + {"esm", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MEXICAN)}, + {"esn", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN)}, + {"esp", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT)}, + {"fin", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)}, + {"finnish", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)}, + {"fra", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)}, + {"frb", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN)}, + {"frc", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_CANADIAN)}, + {"french", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)}, + {"french-belgian", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN)}, + {"french-canadian", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_CANADIAN)}, + {"french-swiss", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_SWISS)}, + {"frs", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_SWISS)}, + {"german", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)}, + {"german-austrian", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN)}, + {"german-swiss", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)}, + {"greek", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)}, + {"hun", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)}, + {"hungarian", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)}, + {"icelandic", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT)}, + {"isl", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT)}, + {"ita", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)}, + {"italian", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)}, + {"italian-swiss", MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN_SWISS)}, + {"its", MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN_SWISS)}, + {"japanese", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)}, + {"jpn", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)}, + {"kor", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)}, + {"korean", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)}, + {"nlb", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN)}, + {"nld", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)}, + {"non", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)}, + {"nor", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL)}, + {"norwegian", MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT)}, + {"norwegian-bokmal", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL)}, + {"norwegian-nynorsk", MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)}, + {"plk", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)}, + {"polish", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)}, + {"portuguese", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE)}, + {"portuguese-brazilian", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN)}, + {"ptb", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN)}, + {"ptg", MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE)}, + {"rus", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)}, + {"russian", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)}, + {"sky", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)}, + {"slovak", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)}, + {"spanish", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT)}, + {"spanish-mexican", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MEXICAN)}, + {"spanish-modern", MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN)}, + {"sve", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)}, + {"swedish", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)}, + {"swiss", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS)}, + {"trk", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)}, + {"turkish", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)}, + {"uk", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)}, + {"us", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)}, + {"usa", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)} +}; + +/* Countries supported are according to "Win32 NLSAPI Functional */ +/* Specification" of 15 September, 1992 */ + +#define CTRY_STR_NUM 68 /* number of country strings + 1 for algorithm */ + +CTRYREC __rg_ctry_rec[] = +{ + {"", 0}, + {"america", CTRY_UNITED_STATES}, + {"aus", CTRY_AUSTRALIA}, + {"australia", CTRY_AUSTRALIA}, + {"austria", CTRY_AUSTRIA}, + {"aut", CTRY_AUSTRIA}, + {"bel", CTRY_BELGIUM}, + {"belgium", CTRY_BELGIUM}, + {"bra", CTRY_BRAZIL}, + {"brazil", CTRY_BRAZIL}, + {"britain", CTRY_UNITED_KINGDOM}, + {"can", CTRY_CANADA}, + {"canada", CTRY_CANADA}, + {"che", CTRY_SWITZERLAND}, + {"china", CTRY_PRCHINA}, + {"chn", CTRY_PRCHINA}, + {"denmark", CTRY_DENMARK}, + {"deu", CTRY_GERMANY}, + {"dnk", CTRY_DENMARK}, + {"england", CTRY_UNITED_KINGDOM}, + {"esp", CTRY_SPAIN}, + {"fin", CTRY_FINLAND}, + {"finland", CTRY_FINLAND}, + {"fra", CTRY_FRANCE}, + {"france", CTRY_FRANCE}, + {"gbr", CTRY_UNITED_KINGDOM}, + {"germany", CTRY_GERMANY}, + {"great britain", CTRY_UNITED_KINGDOM}, + {"holland", CTRY_NETHERLANDS}, + {"iceland", CTRY_ICELAND}, + {"ireland", CTRY_IRELAND}, + {"irl", CTRY_IRELAND}, + {"isl", CTRY_ICELAND}, + {"ita", CTRY_ITALY}, + {"italy", CTRY_ITALY}, + {"japan", CTRY_JAPAN}, + {"jpn", CTRY_JAPAN}, + {"kor", CTRY_SOUTH_KOREA}, + {"korea", CTRY_SOUTH_KOREA}, + {"mex", CTRY_MEXICO}, + {"mexico", CTRY_MEXICO}, + {"netherlands", CTRY_NETHERLANDS}, + {"new zealand", CTRY_NEW_ZEALAND}, + {"new-zealand", CTRY_NEW_ZEALAND}, + {"nld", CTRY_NETHERLANDS}, + {"nor", CTRY_NORWAY}, + {"norway", CTRY_NORWAY}, + {"nz", CTRY_NEW_ZEALAND}, + {"nzl", CTRY_NEW_ZEALAND}, + {"portugal", CTRY_PORTUGAL}, + {"pr china", CTRY_PRCHINA}, + {"pr-china", CTRY_PRCHINA}, + {"prt", CTRY_PORTUGAL}, + {"south korea", CTRY_SOUTH_KOREA}, + {"south-korea", CTRY_SOUTH_KOREA}, + {"spain", CTRY_SPAIN}, + {"swe", CTRY_SWEDEN}, + {"sweden", CTRY_SWEDEN}, + {"switzerland", CTRY_SWITZERLAND}, + {"taiwan", CTRY_TAIWAN}, + {"twn", CTRY_TAIWAN}, + {"uk", CTRY_UNITED_KINGDOM}, + {"united kingdom", CTRY_UNITED_KINGDOM}, + {"united states", CTRY_UNITED_STATES}, + {"united-kingdom", CTRY_UNITED_KINGDOM}, + {"united-states", CTRY_UNITED_STATES}, + {"us", CTRY_UNITED_STATES}, + {"usa", CTRY_UNITED_STATES}, +}; + +#define MAX_LANG_PER_CTRY 3 /* Switzerland has three languages*/ +#define MAX_CTRY_NUM 86 /* Ignore high digit (Max=China[86]=Taiwan[886])*/ +WORD __rgrgwlang[MAX_CTRY_NUM + 1][MAX_LANG_PER_CTRY] = +{ +/* 0*/ + {0,0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_CAN), + MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_CANADIAN),0}, + {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MEXICAN), + MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN),0}, + {0,0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +/* 10*/ + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +/* 20*/ + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +/* 30*/ + {0,0,0}, + {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH),0,0}, + {MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), + MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_BELGIAN),0}, + {MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH),0,0}, + {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH),0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN),0,0}, +/* 40*/ + {0,0,0}, + {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_SWISS), + MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_SWISS), + MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN_SWISS)}, + {0,0,0}, + {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_AUSTRIAN),0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK),0,0}, + + {MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT),0,0}, + {MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT),0,0}, + {MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT),0,0}, + {0,0,0}, + {MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN),0,0}, +/* 50*/ + {0,0,0}, + {MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE),0,0}, + {MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MEXICAN),0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK),0,0}, + {MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT),0,0}, + + {MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN),0,0}, + {0,0,0}, + {0,0,0}, + {MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT),0,0}, + {0,0,0}, +/* 60*/ + {0,0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_AUS),0,0}, + {0,0,0}, + {0,0,0}, + {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_NZ),0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +/* 70*/ + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, +/* 80*/ + {0,0,0}, + {MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT),0,0}, + {MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT),0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {MAKELANGID(LANG_CHINESE,SUBLANG_DEFAULT),0,0} +}; + +/*** +*void pszcpywcs - strcpy, wide char string to char string +* +*Purpose: +* Copies and converts string +* +*Entry: +* psz pszStr - pointer to destination char string +* pwstr pwStr - pointer to source wide char string +* +*Exit: +* None. +* +*Exceptions: +* +*******************************************************************************/ +static VOID pszcpywcs(PSZ pszStr, PWSTR pwStr) +{ + while (*pwStr) + *pszStr++ = (char)(*pwStr++); + *pszStr = 0; +} + +/*** +*WORD trans_lang_lang - translate language string to language id +* +*Purpose: +* convert string to id +* +*Entry: +* pszLang - pointer to language string +* +*Exit: +* translated language id +* +*Exceptions: +* +*******************************************************************************/ +static WORD trans_lang_lang(const PSZ pszLang) +{ + INT i, cmp, low = 0, high = LANG_STR_NUM + 1; + + while (1) + { + i = (low + high) / 2; + + if (!(cmp = stricmp(pszLang, (const char *)__rg_lang_rec[i].szLanguage))) + return __rg_lang_rec[i].wLanguage; /* found the string*/ + else if (cmp < 0) + high = i; /* less than pivot*/ + else + low = i; /* more than pivot*/ + if (low + 1 == high) + return 0; /* not found*/ + } +} + +/*** +*WORD trans_ctry_ctry - translate country string to country id +* +*Purpose: +* convert string to id +* +*Entry: +* pszCtry - pointer to country string +* +*Exit: +* translated country id +* +*Exceptions: +* +*******************************************************************************/ +static WORD trans_ctry_ctry(const PSZ pszCtry) +{ + INT i, cmp, low = 0, high = CTRY_STR_NUM + 1; + + while (1) + { + i = (low + high) / 2; + + if (!(cmp = stricmp(pszCtry, (const char *)__rg_ctry_rec[i].szCountry))) + return __rg_ctry_rec[i].wCountry; /* found the string*/ + else if (cmp < 0) + high = i; /* less than pivot*/ + else + low = i; /* more than pivot*/ + if (low + 1 == high) + return 0; /* not found*/ + } +} + +/*** +*WORD trans_ctry_lang - get default language for a country +* +*Purpose: +* convert country id to language id +* +*Entry: +* wCtry - country id +* +*Exit: +* translated language id +* +*Exceptions: +* +*******************************************************************************/ +static WORD trans_ctry_lang(WORD wCtry) +{ + wCtry %= 100; + if (wCtry > MAX_CTRY_NUM) + return 0; + + return __rgrgwlang[wCtry][0]; +} + +/*** +*BOOL match_ctry_lang - match country with language +* +*Purpose: +* ensure language and country match, choose proper values for language +* and country when matching, country ids converted to proper language id +* +*Entry: +* pwCtry - pointer to country id to match and set +* pwLang - pointer to language id to match and set +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +static BOOL match_ctry_lang(WORD *pwCtry, WORD *pwLang) +{ + UINT i; + WORD wCtry = *pwCtry; + WORD wLang = *pwLang; + WORD wLangT; + + /* only use base 10 two least significant places*/ + wCtry = wCtry % 100; + + if (wCtry > MAX_CTRY_NUM) + return FALSE; + + /* see if any of the sublanguages for this country match*/ + for (i = 0; i < MAX_LANG_PER_CTRY; i++) + { + if (!(wLangT = __rgrgwlang[wCtry][i])) + break; + if (PRIMARYLANGID(wLangT) == PRIMARYLANGID(wLang)) + { + /* they match*/ + if (!SUBLANGID(wLang)) + /* don't override sublanguage*/ + *pwLang = wLangT; + *pwCtry = wLangT; + return TRUE; + } + } + /* get the default language for this country*/ + if (!(*pwCtry = __rgrgwlang[wCtry][0])) + /* bad country number*/ + return FALSE; + return TRUE; +} + +/*** +*BOOL _get_qualified_locale - return fully qualified locale +* +*Purpose: +* get default locale, qualify partially complete locales +* +*Entry: +* dwType - indicates type of lpInput, either QF_STRINGS or QF_LCID +* lpInput - input string/id to be qualified +* lpOutId - pointer to output id, may be NULL if lpOutStr is !NULL +* lpOutStr - pointer to output string, may be NULL if lpOutId is !NULL +* +*Exit: +* TRUE if success, qualified locale is valid +* FALSE if failure +* +*Exceptions: +* +*******************************************************************************/ +BOOL _CRTAPI1 _get_qualified_locale( + const DWORD dwType, + const LPVOID lpInput, + LPLC_ID lpOutId, + LPLC_STRINGS lpOutStr + ) +{ +#if defined _POSIX_ + return FALSE; +#else /* _POSIX_ */ + + LC_ID Id; + WCHAR wcsTemp[MAX_TEMP_STR_LEN]; + + if (!lpOutId && !lpOutStr) + return FALSE; + + /* ----------------------------------------------------------------------- + stage 1: convert input to internal LC_ID. + -----------------------------------------------------------------------*/ + + if (dwType == QF_STRINGS) + { + Id.wLanguage = (WORD)0; + Id.wCountry = (WORD)0; + Id.wCodePage = (WORD)0; + + if (iAslpStr(lpInput)->szLanguage + && *(iAslpStr(lpInput)->szLanguage) + && (!(Id.wLanguage = + trans_lang_lang((const PSZ)iAslpStr(lpInput)->szLanguage)))) + return FALSE; + + if (iAslpStr(lpInput)->szCountry + && *(iAslpStr(lpInput)->szCountry) + && (!(Id.wCountry = + trans_ctry_ctry((const PSZ)iAslpStr(lpInput)->szCountry)))) + return FALSE; + + if (iAslpStr(lpInput)->szCodePage + && *(iAslpStr(lpInput)->szCodePage) + && (!(Id.wCodePage = atoi((const char *)iAslpStr(lpInput)->szCodePage)))) + return FALSE; + } + else if (dwType == QF_LCID) + { + Id = *iAslpId(lpInput); + } + + /* ----------------------------------------------------------------------- + stage 2: qualify internal LC_ID + -----------------------------------------------------------------------*/ + + if (!Id.wLanguage) + { + /* language undefined*/ + if (!Id.wCountry) + { + /* language undefined, country undefined*/ + Id.wLanguage = Id.wCountry = LANGIDFROMLCID(GetUserDefaultLCID()); + if (Id.wCodePage) + { + /* language undefined, country undefined and code page defined*/ + if (IsValidCodePage(Id.wCodePage) == FALSE) + return FALSE; + } + else { + /* language, country and code page undefined*/ + Id.wCodePage = (WORD)GetOEMCP(); + } + } + else + { + /* language undefined, country defined*/ + Id.wCountry = Id.wLanguage = trans_ctry_lang(Id.wCountry); + + if (Id.wCodePage) + { + /* language undefined, country defined and code page defined*/ + if (IsValidCodePage(Id.wCodePage) == FALSE) + return FALSE; + } + else { + /* language undefined, country defined and code page undefined*/ + if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN)) + return FALSE; + Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10); + } + } + } + else + { + /* language defined*/ + if (!Id.wCountry) + { + /* language defined, country undefined*/ + Id.wCountry = Id.wLanguage; + + if (Id.wCodePage) + { + /* language defined, country undefined and code page defined*/ + if (IsValidCodePage(Id.wCodePage) == FALSE) + return FALSE; + } + else { + /* language undefined, country undefined and code page undefined*/ + if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN)) + return FALSE; + Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10); + } + } + else + { + /* language defined, country defined*/ + + /* match and set country and language*/ + if (!match_ctry_lang((WORD *)&Id.wCountry, (WORD *)&Id.wLanguage)) + return FALSE; + + if (Id.wCodePage) + { + /* language defined, country defined and code page defined*/ + if (IsValidCodePage(Id.wCodePage) == FALSE) + return FALSE; + } + else { + /* language defined, country defined and code page undefined*/ + if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, wcsTemp, MAX_TEMP_STR_LEN)) + return FALSE; + Id.wCodePage = (WORD)wcstol(wcsTemp, NULL, 10); + } + } + } + + /* ----------------------------------------------------------------------- + stage 3: convert to proper output format + -----------------------------------------------------------------------*/ + + if (lpOutId) + { + *lpOutId = Id; + } + + if (lpOutStr) + { + if (!GetLocaleInfoW(MAKELCID(Id.wLanguage, SORT_DEFAULT), LOCALE_SENGLANGUAGE, wcsTemp, MAX_LANG_LEN)) + return FALSE; + pszcpywcs((PSZ)lpOutStr->szLanguage, (PWSTR)wcsTemp); + + if (!GetLocaleInfoW(MAKELCID(Id.wCountry, SORT_DEFAULT), LOCALE_SENGCOUNTRY, wcsTemp, MAX_CTRY_LEN)) + return FALSE; + pszcpywcs((PSZ)lpOutStr->szCountry, (PWSTR)wcsTemp); + + _itoa((int)Id.wCodePage, (char *)lpOutStr->szCodePage, 10); + } + return TRUE; +#endif /* _POSIX_ */ +} + + +/* for testing when new items added to tables */ + +#if 0 + +VOID _CRTAPI1 test_lang_table(VOID) +{ + UINT i; + + printf("Testing Language Table\n"); + printf("Real Table Size = %d entries, defined size=%d entries\n", + sizeof(__rg_lang_rec) / sizeof(LANGREC), LANG_STR_NUM); + for (i = 0; i < LANG_STR_NUM-1; i++) + { + printf("language name[%d] = '%s' number=%d\n", i, __rg_lang_rec[i].szLanguage, __rg_lang_rec[i].wLanguage); + if ((stricmp(__rg_lang_rec[i].szLanguage,__rg_lang_rec[i+1].szLanguage) >= 0)) + printf("\n*********\nBad Lang Table Lang[%d]=%s Lang[%d]=%s\n\n", + i, __rg_lang_rec[i].szLanguage, i+1, __rg_lang_rec[i+1].szLanguage); + } + printf("language name[%d] = '%s' number=%d\n", i, __rg_lang_rec[i].szLanguage, __rg_lang_rec[i].wLanguage); +} + +VOID _CRTAPI1 test_ctry_table(VOID) +{ + UINT i; + + printf("Testing Country Table\n"); + printf("Real Table Size = %d entries, defined size=%d entries\n", + sizeof(__rg_ctry_rec) / sizeof(CTRYREC), CTRY_STR_NUM); + for (i = 0; i < CTRY_STR_NUM-1; i++) + { + printf("country name[%d] = '%s' number=%d\n", i, __rg_ctry_rec[i].szCountry, __rg_ctry_rec[i].wCountry); + if ((stricmp(__rg_ctry_rec[i].szCountry,__rg_ctry_rec[i+1].szCountry) >= 0)) + printf("\n**********\nBad Ctry Table Ctry[%d]=%s Ctry[%d]=%s\n\n", + i, __rg_ctry_rec[i].szCountry, i+1, __rg_ctry_rec[i+1].szCountry); + } + printf("country name[%d] = '%s' number=%d\n", i, __rg_ctry_rec[i].szCountry, __rg_ctry_rec[i].wCountry); +} + +#endif diff --git a/private/crt32/misc/i386/_initone.asm b/private/crt32/misc/i386/_initone.asm new file mode 100644 index 000000000..90d901904 --- /dev/null +++ b/private/crt32/misc/i386/_initone.asm @@ -0,0 +1,17 @@ + page ,132 + +;******* +; +; Alternate form of CINITONE.ASM +; +; The MIPS C Compiler does not prepend underscores to C +; variables and functions like the I386 C Compiler does. +; +; The EQUate below will yield an object file +; which will be appropriate for MIPS COFF format. +; +;******* + +NO_UNDERSCORE equ 1 + +include i386\cinitone.asm diff --git a/private/crt32/misc/i386/cinitone.asm b/private/crt32/misc/i386/cinitone.asm new file mode 100644 index 000000000..e4bf0ef39 --- /dev/null +++ b/private/crt32/misc/i386/cinitone.asm @@ -0,0 +1,78 @@ + page ,132 + title cinitone - C Run-Time Initialization for _onexit/atexit +;*** +;cinitone.asm - WIN32 C Run-Time Initialization for _onexit()/atexit() routines +; +; Copyright (c) 1992, Microsoft Corporation. All rights reserved. +; +;Purpose: +; Initialization entry for the _onexit()/atexit() functions. +; This module adds an entry for _onexitinit() to the initializer table. +; ONEXIT.C references the dummy variable __c_onexit in order to force +; the loading of this module. +; +;Notes: +; +;Revision History: +; 03-19-92 SKS Module created. +; 03-24-92 SKS Added MIPS support (NO_UNDERSCORE) +; 04-30-92 SKS Add "offset FLAT:" to get correct fixups for OMF objs +; 08-06-92 SKS Revised to use new section names and macros +; +;******************************************************************************* + +.xlist +include cruntime.inc +include defsects.inc +.list + +ifndef _WIN32_ +.err +%out _WIN32_ MUST be defined! +endif + + +ifndef NO_UNDERSCORE ; I386 VERSION ************************* + + + extrn _onexitinit:NEAR + + +beginSection XIC + + dd offset FLAT: _onexitinit + +endSection XIC + + + .DATA + + public __c_onexit + +__c_onexit dd 0 + + +else ; NO_UNDERSCORE ; MIPS VERSION ************************* + + + extrn onexitinit:NEAR + + +beginSection XIC + + dd offset FLAT: onexitinit + +endSection XIC + + + .DATA + + public _c_onexit + +_c_onexit dd 0 + + +endif ; NO_UNDERSCORE ; **** VERSION ************************* + + + end diff --git a/private/crt32/misc/i386/exsup.asm b/private/crt32/misc/i386/exsup.asm new file mode 100644 index 000000000..8e7043eca --- /dev/null +++ b/private/crt32/misc/i386/exsup.asm @@ -0,0 +1,299 @@ +;*** +;exsup.asm +; +; Copyright (c) 1993-1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Exception handling for i386. This file contains those routines +; common to both C8.0 and C9.0. +; +;Notes: +; +;Revision History: +; 04-13-93 JWM setjmp(), longjmp() & raisex() moved to setjmp.asm; +; common data definitions moved to exsup.inc. +; 10-18-93 GJF Ensure direction flag is clear in _except_handler2 +; 12-16-93 PML Accept <0,0,>0 from except filter, not just -1,0,+1 +; 01-10-94 PML Moved C8-specific __except_handler2 to exsup2.inc. +; Only C8/C9 common routines left here. +; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not +; 0. +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +ifdef _WIN32_ +_WIN32_OR_POSIX_ equ 1 +endif +ifdef _POSIX_ +_WIN32_OR_POSIX_ equ 1 +endif + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +;REVIEW: can we get rid of _global_unwind2, and just use +; the C runtimes version, _global_unwind? + +ifdef _WIN32_OR_POSIX_ +extrn _RtlUnwind@16:near +endif + +;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION; +;struct _EXCEPTION_REGISTRATION{ +; struct _EXCEPTION_REGISTRATION *prev; +; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD); +; struct scopetable_entry *scopetable; +; int trylevel; +;}; +_EXCEPTION_REGISTRATION_COMMON struc ; C8.0/C9.0 common only + dd ? ; prev (OS-req, def'd in exsup.inc) + dd ? ; handler (ditto) +scopetable dd ? ; C8/C9 common +trylevel dd ? ; C8/C9 common +_EXCEPTION_REGISTRATION_COMMON ends + +;#define EXCEPTION_MAXIMUM_PARAMETERS 4 +;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; +;struct _EXCEPTION_RECORD{ +; NTSTATUS ExceptionCode; +; ULONG ExceptionFlags; +; struct _EXCEPTION_RECORD *ExceptionRecord; +; PVOID ExceptionAddress; +; ULONG NumberParameters; +; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; +;}; +_EXCEPTION_RECORD struc + exception_number dd ? + exception_flags dd ? + exception_record dd ? + exception_address dd ? + number_parameters dd ? + exception_information dd 4 dup(?) +_EXCEPTION_RECORD ends +SIZEOF_EXCEPTION_RECORD equ 36 + +assumes DS,DATA +assumes FS,DATA + +public __except_list +__except_list equ 0 + +;struct _SCOPETABLE_ENTRY{ +; int enclosing_level; /* lexical level of enclosing scope */ +; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */ +; void (*specific_handler)(void); /* xcpt or termination handler */ +;}; +;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS]; +_SCOPETABLE_ENTRY struc + enclosing_level dd ? + filter dd ? + specific_handler dd ? +_SCOPETABLE_ENTRY ends + +BeginCODE +if @Version LT 600 +ifdef _WIN32_OR_POSIX_ +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +else +assumes CS,CODE +endif +endif + +ifdef _WIN32_OR_POSIX_ ;{ + +;NB: call to RtlUnwind appears to trash ebx! and possibly others so just +; to be save, we save all callee save regs. +cProc _global_unwind2,<C,PUBLIC>,<IBX,ISI,IDI,IBP> + parmDP stop +cBegin + push 0 ; ReturnValue + push 0 ; ExceptionRecord + push offset flat:_gu_return ; TargetIp + push stop ; TargetFrame + + call _RtlUnwind@16 +_gu_return: +cEnd + +else ;}{ + +;/* _GLOBAL_UNWIND2 - */ +;void _global_unwind2(PEXCEPTION_REGISTRATION *stop) +;{ +; for(xr=__except_list; xr!=stop; xr=xr->prev){ +; assert(xr!=NULL); +; /* NOTE: must set ebp to this scopes frame before call */ +; _local_unwind2(xr, -1); +; } +;} +cProc _global_unwind2,<C,PUBLIC>,<ISI,IDI> + parmDP stop + localV xr,SIZEOF_EXCEPTION_RECORD +cBegin + ;build an EXCEPTION_RECORD to pass to language handler for unwinding + lea esi, xr + mov [esi.exception_number], 0 + mov [esi.exception_flags], EXCEPTION_UNWIND_CONTEXT + ;REVIEW: fill in the rest of the struct? + + mov edi, dword ptr fs:__except_list +_gu_top: + cmp edi, stop + je short _gu_done + cmp edi, -1 ; -1 means no higher-level handler + je short _gu_error + + push edi + push esi + call [edi.handler] + add esp, 8 + + mov edi, [edi.prev] + mov dword ptr fs:__except_list, edi + jmp short _gu_top + +_gu_error: + ;assert(0); + +_gu_done: +cEnd + +endif ;} + +;_unwind_handler( +; PEXCEPTION_RECORD xr, +; PREGISTRATION_RECORD establisher, +; PCONTEXT context, +; PREGISTRATION_RECORD dispatcher); +; +;this is a special purpose handler used to guard our local unwinder. +; its job is to catch collided unwinds. +; +;NB: this code is basically stolen from the NT routine xcptmisc.asm +; and is basically the same method used by the system unwinder (RtlUnwind). +; +cProc _unwind_handler,<C> +cBegin + mov ecx, dword ptr [esp+4] + test dword ptr [ecx.exception_flags], EXCEPTION_UNWIND_CONTEXT + mov eax, DISPOSITION_CONTINUE_SEARCH + jz short _uh_return + + ; We collide in a _local_unwind. We set the dispatched to the + ; establisher just before the local handler so we can unwind + ; any future local handlers. + + mov eax, [esp+8] ; Our establisher is the one + ; in front of the local one + + mov edx, [esp+16] + mov [edx], eax ; set dispatcher to local_unwind2 + + mov eax, DISPOSITION_COLLIDED_UNWIND +_uh_return: +cEnd + +;/* _LOCAL_UNWIND2 - run all termination handlers listed in the scope table +; * associated with the given registration record, from the current lexical +; * level through enclosing levels up to, but not including the given 'stop' +; * level. +; */ +;void _local_unwind2(PEXCEPTION_REGISTRATION xr, int stop) +;{ +; int ix; +; +; for(ix=xr->trylevel; ix!=-1 && ix!=stop; ix=xr->xscope[i].enclosing_level){ +; /* NULL indicates that this entry is for a termination handler */ +; if(xr->xscope[i].filter==NULL){ +; /* NB: call to the termination handler may trash callee save regs */ +; (*xr->xscope[i].specific_handler)(); +; } +; } +; xr->trylevel=stop; +;} +;/* NOTE: frame (ebp) is setup by caller of __local_unwind2 */ +cProc _local_unwind2,<C,PUBLIC> +cBegin + push ebx + push esi + push edi ;call to the handler may trash, so we must save it + + mov eax, [esp+16] ; (eax) = PEXCEPTION_REGISTRATION + + ;link in a handler to guard our unwind + push eax + push TRYLEVEL_INVALID + push OFFSET FLAT:__unwind_handler + push fs:__except_list + mov fs:__except_list, esp + +_lu_top: + mov eax, [esp+32] ; (eax) = PEXCEPTION_REGISTRATION + mov ebx, [eax.scopetable] + mov esi, [eax.trylevel] + + cmp esi, -1 ; REVIEW: do we need this extra check? + je short _lu_done + cmp esi, [esp+36] + je short _lu_done + + lea esi, [esi+esi*2] ; esi*= 3 + + mov ecx, [(ebx+esi*4).enclosing_level] + mov [esp+8], ecx ; save enclosing level + mov [eax.trylevel], ecx + + cmp dword ptr [(ebx+esi*4).filter], 0 + jnz short _lu_continue + + call [(ebx+esi*4).specific_handler] + +_lu_continue: + jmp short _lu_top + +_lu_done: + pop fs:__except_list + add esp, 4*3 ; cleanup stack + + pop edi ; restore c-runtime registers + pop esi + pop ebx +cEnd + +;/* _ABNORMAL_TERMINATION - return TRUE if __finally clause entered via +; * _local_unwind2. +; */ +;BOOLEAN _abnormal_termination(void); +cProc _abnormal_termination,<C,PUBLIC> +cBegin + xor eax, eax ; assume FALSE + + mov ecx, fs:__except_list + cmp [ecx.handler], offset FLAT:__unwind_handler + jne short _at_done ; UnwindHandler first? + + mov edx, [ecx+12] ; establisher of local_unwind2 + mov edx, [edx.trylevel] ; is trylevel the same as the + cmp [ecx+8], edx ; local_unwind level? + jne short _at_done ; no - then FALSE + + mov eax, 1 ; currently in _abnormal_termination +_at_done: +cEnd + + +EndCODE +END diff --git a/private/crt32/misc/i386/exsup2.asm b/private/crt32/misc/i386/exsup2.asm new file mode 100644 index 000000000..ead56f5af --- /dev/null +++ b/private/crt32/misc/i386/exsup2.asm @@ -0,0 +1,271 @@ +;*** +;exsup2.asm +; +; Copyright (c) 1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Exception handling for i386. This is just the C8.0 version of +; the language-specific exception handler. The C9.0 version is +; found in exsup3.asm, and the routines common to both C8 and C9 +; are found in exsup.asm. +; +;Notes: +; +;Revision History: +; 01-10-94 PML Created with __except_handler2 from exsup.asm +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +ifdef _WIN32_ +_WIN32_OR_POSIX_ equ 1 +endif +ifdef _POSIX_ +_WIN32_OR_POSIX_ equ 1 +endif + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +;REVIEW: can we get rid of _global_unwind2, and just use +; the C runtimes version, _global_unwind? + +extrn __global_unwind2:near +extrn __local_unwind2:near + +;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION; +;struct _EXCEPTION_REGISTRATION{ +; struct _EXCEPTION_REGISTRATION *prev; +; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD); +; struct scopetable_entry *scopetable; +; int trylevel; +; int _ebp; +; PEXCEPTION_POINTERS xpointers; +;}; +_C8_EXCEPTION_REGISTRATION struc ; C8.0 version + dd ? ; prev (common) + dd ? ; handler (common) +;private: + scopetable dd ? + trylevel dd ? + _ebp dd ? + xpointers dd ? +_C8_EXCEPTION_REGISTRATION ends + +;#define EXCEPTION_MAXIMUM_PARAMETERS 4 +;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; +;struct _EXCEPTION_RECORD{ +; NTSTATUS ExceptionCode; +; ULONG ExceptionFlags; +; struct _EXCEPTION_RECORD *ExceptionRecord; +; PVOID ExceptionAddress; +; ULONG NumberParameters; +; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; +;}; +_EXCEPTION_RECORD struc + exception_number dd ? + exception_flags dd ? + exception_record dd ? + exception_address dd ? + number_parameters dd ? + exception_information dd 4 dup(?) +_EXCEPTION_RECORD ends +SIZEOF_EXCEPTION_RECORD equ 36 + +;/* following is the structure returned by the _exception_info() intrinsic. */ +;typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS; +;typedef struct EXCEPTION_POINTERS *PEXCEPTION_POINTERS; +;struct _EXCEPTION_POINTERS{ +; PEXCEPTION_RECORD ExceptionRecord; +; PCONTEXT Context; +;}; +_EXCEPTION_POINTERS struc + ep_xrecord dd ? + ep_context dd ? +_EXCEPTION_POINTERS ends +SIZEOF_EXCEPTION_POINTERS equ 8 + +assumes DS,DATA +assumes FS,DATA + +__except_list equ 0 + +;struct _SCOPETABLE_ENTRY{ +; int enclosing_level; /* lexical level of enclosing scope */ +; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */ +; void (*specific_handler)(void); /* xcpt or termination handler */ +;}; +;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS]; +_SCOPETABLE_ENTRY struc + enclosing_level dd ? + filter dd ? + specific_handler dd ? +_SCOPETABLE_ENTRY ends + +BeginCODE +if @Version LT 600 +ifdef _WIN32_OR_POSIX_ +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +else +assumes CS,CODE +endif +endif + +;/* _EXCEPT_HANDLER2 - Try to find an exception handler listed in the scope +; * table associated with the given registration record, that wants to accept +; * the current exception. If we find one, run it (and never return). +; * RETURNS: (*if* it returns) +; * DISPOSITION_DISMISS - dismiss the exception. +; * DISPOSITION_CONTINUE_SEARCH - pass the exception up to enclosing handlers +; */ +;int _except_handler2( +; PEXCEPTION_RECORD exception_record, +; PEXCEPTION_REGISTRATION registration, +; PCONTEXT context, +; PEXCEPTION_REGISTRATION dispatcher) +;{ +; int ix, filter_result; +; +; for(ix=registration->trylevel; ix!=-1; ix=registration->xscope[ix].enclosing_level){ +; /* if filter==NULL, then this is an entry for a termination handler */ +; if(registration->xscope[ix].filter){ +; /* NB: call to the filter may trash the callee save +; registers. (this is *not* a standard cdecl function) */ +; filter_result=(*registration->xscope[ix].filter)(xinfo); +; if(filter_result==FILTER_DISMISS) +; return(-1); /* dismiss */ +; if(filter_result==FILTER_ACCEPT){ +; _global_unwind2(registration); +; _local_unwind2(registration, ix); +; (*registration->xscope[ix].specific_handler)(void); +; assert(UNREACHED); /*should never return from handler*/ +; } +; assert(filter_result==FILTER_CONTINUE_SEARCH); +; } +; } +; return(0); /* didnt find one */ +;} + db 'VC10' ;; VC/C++ 1.0/32-bit (C8.0) version + db 'XC00' ;; so debugger can recognize this proc (cuda:3936) +cProc _except_handler2,<C,PUBLIC>,<IBX,ISI,IDI,IBP> + parmDP xrecord + parmDP registration + parmDP context + parmDP dispatcher + localV xp,SIZEOF_EXCEPTION_POINTERS +cBegin + ;4*4b for callee saves + 4b return address + 4b param = 24 + + ;DF in indeterminate state at time of exception, so clear it + cld + + mov ebx, registration ;ebx= PEXCEPTION_REGISTRATION + mov eax, xrecord + + test [eax.exception_flags], EXCEPTION_UNWIND_CONTEXT + jnz short _lh_unwinding + + ;build the EXCEPTION_POINTERS locally store its address in the + ; registration record. this is the pointer that is returned by + ; the _eception_info intrinsic. + mov xp.ep_xrecord, eax + mov eax, context + mov xp.ep_context, eax + lea eax, xp + mov [ebx.xpointers], eax + + mov esi, [ebx.trylevel] ;esi= try level + mov edi, [ebx.scopetable] ;edi= scope table base +_lh_top: + cmp esi, -1 + je short _lh_bagit + lea ecx, [esi+esi*2] ;ecx= trylevel*3 + cmp dword ptr [(edi+ecx*4).filter], 0 + je short _lh_continue ;term handler, so keep looking + + ;filter may trash *all* registers, so save ebp and scopetable offset + push esi + push ebp + + mov ebp, [ebx._ebp] + call [(edi+ecx*4).filter] ;call the filter + + pop ebp + pop esi + ;ebx may have been trashed by the filter, so we must reload + mov ebx, registration + + ; Accept <0, 0, >0 instead of just -1, 0, +1 + or eax, eax + jz short _lh_continue + js short _lh_dismiss + ;assert(eax==FILTER_ACCEPT) + + ;reload xscope base, cuz it was trashed by the filter call + mov edi, [ebx.scopetable] + ;load handler address before we loose components of address mode + push ebx ;registration* + call __global_unwind2 ;run term handlers + add esp, 4 + + ;setup ebp for the local unwinder and the specific handler + mov ebp, [ebx._ebp] + + ;the stop try level == accepting except level + push esi ;stop try level + push ebx ;registration* + call __local_unwind2 + add esp, 8 + + lea ecx, [esi+esi*2] ;ecx=trylevel*3 +; set the current trylevel to our enclosing level immediately +; before giving control to the handler. it is the enclosing +; level, if any, that guards the handler. + mov eax, [(edi+ecx*4).enclosing_level] + mov [ebx.trylevel], eax + call [(edi+ecx*4).specific_handler] ;call the except handler + ;assert(0) ;(NB! should not return) + +_lh_continue: + ;reload the scope table base, possibly trashed by call to filter + mov edi, [ebx.scopetable] + lea ecx, [esi+esi*2] + mov esi, [edi+ecx*4+0] ;load the enclosing trylevel + jmp short _lh_top + +_lh_dismiss: + mov eax, DISPOSITION_DISMISS ;dismiss the exception + jmp short _lh_return + +_lh_bagit: + mov eax, DISPOSITION_CONTINUE_SEARCH + jmp short _lh_return + +_lh_unwinding: + push ebp + mov ebp, [ebx._ebp] + push -1 + push ebx + call __local_unwind2 + add esp, 8 + pop ebp + ;the return value is not really relevent in an unwind context + mov eax, DISPOSITION_CONTINUE_SEARCH + +_lh_return: +cEnd + +EndCODE +END diff --git a/private/crt32/misc/i386/exsup3.asm b/private/crt32/misc/i386/exsup3.asm new file mode 100644 index 000000000..ff8a91dfa --- /dev/null +++ b/private/crt32/misc/i386/exsup3.asm @@ -0,0 +1,290 @@ +;*** +;exsup3.asm +; +; Copyright (c) 1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Exception handling for i386. This is just the C9.0 version of +; the language-specific exception handler. The C8.0 version is +; found in exsup2.asm, and the routines common to both C8 and C9 +; are found in exsup.asm. +; +;Notes: +; +;Revision History: +; 01-10-94 PML Create VC/C++ 2.0 (C9.0) version from C8.0 original +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +ifdef _WIN32_ +_WIN32_OR_POSIX_ equ 1 +endif +ifdef _POSIX_ +_WIN32_OR_POSIX_ equ 1 +endif + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +;REVIEW: can we get rid of _global_unwind2, and just use +; the C runtimes version, _global_unwind? + +extrn __global_unwind2:near +extrn __local_unwind2:near + +;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION; +;struct _EXCEPTION_REGISTRATION{ +;/* _esp, xpointers at negative offset */ +; int _esp; +; PEXCEPTION_POINTERS xpointers; +; struct _EXCEPTION_REGISTRATION *prev; +; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD); +; struct scopetable_entry *scopetable; +; int trylevel; +;}; +;private (at negative offsets from node ptr) + _esp = -8 + xpointers = -4 +_C9_EXCEPTION_REGISTRATION struc ; C9.0 version +;public: + dd ? ; prev (common) + dd ? ; handler (common) +;private: + scopetable dd ? + trylevel dd ? +_C9_EXCEPTION_REGISTRATION ends +FRAME_EBP_OFFSET equ 16 + +;#define EXCEPTION_MAXIMUM_PARAMETERS 4 +;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD; +;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD; +;struct _EXCEPTION_RECORD{ +; NTSTATUS ExceptionCode; +; ULONG ExceptionFlags; +; struct _EXCEPTION_RECORD *ExceptionRecord; +; PVOID ExceptionAddress; +; ULONG NumberParameters; +; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; +;}; +_EXCEPTION_RECORD struc + exception_number dd ? + exception_flags dd ? + exception_record dd ? + exception_address dd ? + number_parameters dd ? + exception_information dd 4 dup(?) +_EXCEPTION_RECORD ends +SIZEOF_EXCEPTION_RECORD equ 36 + +;/* following is the structure returned by the _exception_info() intrinsic. */ +;typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS; +;typedef struct EXCEPTION_POINTERS *PEXCEPTION_POINTERS; +;struct _EXCEPTION_POINTERS{ +; PEXCEPTION_RECORD ExceptionRecord; +; PCONTEXT Context; +;}; +_EXCEPTION_POINTERS struc + ep_xrecord dd ? + ep_context dd ? +_EXCEPTION_POINTERS ends +SIZEOF_EXCEPTION_POINTERS equ 8 + +assumes DS,DATA +assumes FS,DATA + +__except_list equ 0 + +;struct _SCOPETABLE_ENTRY{ +; int enclosing_level; /* lexical level of enclosing scope */ +; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */ +; void (*specific_handler)(void); /* xcpt or termination handler */ +;}; +;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS]; +_SCOPETABLE_ENTRY struc + enclosing_level dd ? + filter dd ? + specific_handler dd ? +_SCOPETABLE_ENTRY ends + +BeginCODE +if @Version LT 600 +ifdef _WIN32_OR_POSIX_ +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +else +assumes CS,CODE +endif +endif + +;/* _EXCEPT_HANDLER3 - Try to find an exception handler listed in the scope +; * table associated with the given registration record, that wants to accept +; * the current exception. If we find one, run it (and never return). +; * RETURNS: (*if* it returns) +; * DISPOSITION_DISMISS - dismiss the exception. +; * DISPOSITION_CONTINUE_SEARCH - pass the exception up to enclosing handlers +; */ +;int _except_handler3( +; PEXCEPTION_RECORD exception_record, +; PEXCEPTION_REGISTRATION registration, +; PCONTEXT context, +; PEXCEPTION_REGISTRATION dispatcher) +;{ +; int ix, filter_result; +; +; for(ix=registration->trylevel; ix!=-1; ix=registration->xscope[ix].enclosing_level){ +; /* if filter==NULL, then this is an entry for a termination handler */ +; if(registration->xscope[ix].filter){ +; /* NB: call to the filter may trash the callee save +; registers. (this is *not* a standard cdecl function) */ +; filter_result=(*registration->xscope[ix].filter)(xinfo); +; if(filter_result==FILTER_DISMISS) +; return(-1); /* dismiss */ +; if(filter_result==FILTER_ACCEPT){ +; _global_unwind2(registration); +; _local_unwind2(registration, ix); +; (*registration->xscope[ix].specific_handler)(void); +; assert(UNREACHED); /*should never return from handler*/ +; } +; assert(filter_result==FILTER_CONTINUE_SEARCH); +; } +; } +; return(0); /* didnt find one */ +;} + db 'VC20' ;; VC/C++ 2.0/32-bit (C9.0) version + db 'XC00' ;; so debugger can recognize this proc (cuda:3936) +cProc _except_handler3,<C,PUBLIC>,<IBX,ISI,IDI,IBP> + parmDP xrecord + parmDP registration + parmDP context + parmDP dispatcher + localV xp,SIZEOF_EXCEPTION_POINTERS +cBegin + ;4*4b for callee saves + 4b return address + 4b param = 24 + + ;DF in indeterminate state at time of exception, so clear it + cld + + mov ebx, registration ;ebx= PEXCEPTION_REGISTRATION + mov eax, xrecord + + test [eax.exception_flags], EXCEPTION_UNWIND_CONTEXT + jnz short _lh_unwinding + + ;build the EXCEPTION_POINTERS locally store its address in the + ; registration record. this is the pointer that is returned by + ; the _eception_info intrinsic. + mov xp.ep_xrecord, eax + mov eax, context + mov xp.ep_context, eax + lea eax, xp + mov [ebx.xpointers], eax + + mov esi, [ebx.trylevel] ;esi= try level + mov edi, [ebx.scopetable] ;edi= scope table base +_lh_top: + cmp esi, -1 + je short _lh_bagit + lea ecx, [esi+esi*2] ;ecx= trylevel*3 + cmp dword ptr [(edi+ecx*4).filter], 0 + je short _lh_continue ;term handler, so keep looking + + ;filter may trash *all* registers, so save ebp and scopetable offset + push esi + push ebp + + lea ebp, FRAME_EBP_OFFSET[ebx] + call [(edi+ecx*4).filter] ;call the filter + + pop ebp + pop esi + ;ebx may have been trashed by the filter, so we must reload + mov ebx, registration + + ; Accept <0, 0, >0 instead of just -1, 0, +1 + or eax, eax + jz short _lh_continue + js short _lh_dismiss + ;assert(eax==FILTER_ACCEPT) + + ;reload xscope base, cuz it was trashed by the filter call + mov edi, [ebx.scopetable] + ;load handler address before we loose components of address mode + push ebx ;registration* + call __global_unwind2 ;run term handlers + add esp, 4 + + ;setup ebp for the local unwinder and the specific handler + lea ebp, FRAME_EBP_OFFSET[ebx] + + ;the stop try level == accepting except level + push esi ;stop try level + push ebx ;registration* + call __local_unwind2 + add esp, 8 + + lea ecx, [esi+esi*2] ;ecx=trylevel*3 +; set the current trylevel to our enclosing level immediately +; before giving control to the handler. it is the enclosing +; level, if any, that guards the handler. + mov eax, [(edi+ecx*4).enclosing_level] + mov [ebx.trylevel], eax + call [(edi+ecx*4).specific_handler] ;call the except handler + ;assert(0) ;(NB! should not return) + +_lh_continue: + ;reload the scope table base, possibly trashed by call to filter + mov edi, [ebx.scopetable] + lea ecx, [esi+esi*2] + mov esi, [edi+ecx*4+0] ;load the enclosing trylevel + jmp short _lh_top + +_lh_dismiss: + mov eax, DISPOSITION_DISMISS ;dismiss the exception + jmp short _lh_return + +_lh_bagit: + mov eax, DISPOSITION_CONTINUE_SEARCH + jmp short _lh_return + +_lh_unwinding: + push ebp + lea ebp, FRAME_EBP_OFFSET[ebx] + push -1 + push ebx + call __local_unwind2 + add esp, 8 + pop ebp + ;the return value is not really relevent in an unwind context + mov eax, DISPOSITION_CONTINUE_SEARCH + +_lh_return: +cEnd + +public __seh_longjmp_unwind@4 +__seh_longjmp_unwind@4 proc near + push ebp + mov ecx, 8[esp] + mov ebp, [ecx.saved_ebp] + mov eax, [ecx.saved_trylevel] + push eax + mov eax, [ecx.saved_xregistration] + push eax + call __local_unwind2 + add esp, 8 + pop ebp + ret 4 +__seh_longjmp_unwind@4 endp + +EndCODE +END diff --git a/private/crt32/misc/i386/longjmp.asm b/private/crt32/misc/i386/longjmp.asm new file mode 100644 index 000000000..ae236afff --- /dev/null +++ b/private/crt32/misc/i386/longjmp.asm @@ -0,0 +1,150 @@ +;*** +;longjmp.asm +; +; Copyright (C) 1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Contains setjmp(), longjmp() & raisex() routines; +; split from exsup.asm for granularity purposes. +; +;Notes: +; +;Revision History: +; 01-12-94 PML Split from setjmp.asm, added C9.0 generic EH +; callback for unwind. +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +BeginDATA + +COMM __setjmpexused:dword + +EndDATA + +assumes DS,DATA +assumes FS,DATA + +BeginCODE +if @Version LT 600 +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +endif + +; Following symbols defined in exsup.asm, sehsupp.c +extrn __except_list:near +extrn __global_unwind2:near +extrn __local_unwind2:near +extrn __rt_probe_read4@4:near + +; int +; longjmp ( +; IN jmp_buf env +; IN int val) +; +; Routine Description: +; +; Restore the stack and register environment saved by _setjmp. +; Reloads callee-save registers and stack pointer to that saved in +; the jmp_buf, then returns to the point of the _setjmp call. +; +; If exception unwinding is enabled, also reload the exception state +; from the jmp_buf by doing an unwind (both global and local) back +; to the old state. Do so by checking for a new-format (C9.0) +; jmp_buf, and call the EH longjmp unwinder saved therein if +; found, else assume a C8.0-vintage jmp_buf and SEH. +; +; Arguments: +; +; env - Address of the buffer holding the reload state +; val - Value to return from the _setjmp callsite (if nonzero) +; +; Return Value: +; +; None. longjmp does not return directly, but instead continues +; execution from the point of the _setjmp used to initialize the +; jmp_buf. That call will return the 'val' parameter if nonzero, +; else a one. + +cProc longjmp,<C,PUBLIC> +cBegin + mov ebx, [esp+4] ;get jmp_buf + + ;restore ebp before possible call to local_unwind-er + ; the call to global/local unwind will preserve this (callee save). + mov ebp, [ebx.saved_ebp] ;set up bp +ifdef _NTSDK + cmp __setjmpexused, 0 + je short _lj_no_unwind +endif + mov esi, [ebx.saved_xregistration] + cmp esi, dword ptr fs:__except_list + je short _lj_local_unwind + + push esi + call __global_unwind2 + add esp,4 + +_lj_local_unwind: + cmp esi, 0 + je short _lj_no_unwind + + ; Check if called with old or new format jmp_buf. Look for the + ; version cookie that's only present in the new format. + lea eax, [ebx.version_cookie] + push eax + call __rt_probe_read4@4 + or eax, eax + jz short _lj_old_unwind + mov eax, [ebx.version_cookie] + cmp eax, JMPBUF_COOKIE + jnz short _lj_old_unwind + + ; Called with a new-format jmp_buf. Call unwind function supplied + ; to the jmp_buf at setjmp time. + mov eax, [ebx.unwind_func] + or eax, eax + jz short _lj_no_unwind ;no local unwind necessary + push ebx + call eax + jmp short _lj_no_unwind + + ; Called with an old-format jmp_buf. Duplicate old longjmp behavior, + ; assuming there's a C8.0 SEH node at top. +_lj_old_unwind: + mov eax, [ebx.saved_trylevel] + push eax + push esi + call __local_unwind2 + add esp, 8 + +_lj_no_unwind: + mov edx, ebx + mov ebx, [edx.saved_ebx] ;recover registers... + mov edi, [edx.saved_edi] + mov esi, [edx.saved_esi] + + mov eax, [esp+8] ;load the return value + cmp eax, 1 ;make sure it's not 0 + adc eax, 0 + + mov esp, [edx.saved_esp] ;here, sp gets scorched + add esp, 4 ;punt the (old) return address + jmp [edx.saved_return] ;return +cEnd + +EndCODE +END diff --git a/private/crt32/misc/i386/sehsupp.c b/private/crt32/misc/i386/sehsupp.c new file mode 100644 index 000000000..1dbce51bb --- /dev/null +++ b/private/crt32/misc/i386/sehsupp.c @@ -0,0 +1,59 @@ +/*** +*sehsupp.c - helper functions for Structured Exception Handling support +* +* Copyright (C) 1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains _rt_probe_read. Helper for the SEH runtime support +* routines (longjmp in particular). Much of the SEH code is written +* in asm, so these routines are available when probing memory in ways +* that must be guarded with __try/__except in case of access violation. +* +*Revision History: +* 12-05-93 PML Module created. +* 12-22-93 GJF Made #define WIN32_LEAN_AND_MEAN conditional. +* 01-12-94 PML Rewritten - still need helpers, just different ones +* +*******************************************************************************/ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#include <windows.h> + +/*** +*BOOL __stdcall _rt_probe_read4 - Check if a DWORD is readable +* +*Purpose: +* Internal support function called by longjmp. Check if a DWORD is +* readable under a __try/__except. +* +*Entry: +* DWORD * p - Pointer to DWORD to be probed +* +*Exit: +* Success: TRUE - Able to read +* Failure: FALSE - Access violation while reading +* +******************************************************************************/ + +BOOL __stdcall _rt_probe_read4( + DWORD * ptr) +{ + BOOL readable; + + __try + { + *(volatile DWORD *)ptr; + readable = TRUE; + } + __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) + { + readable = FALSE; + } + + return readable; +} diff --git a/private/crt32/misc/i386/setjmp.asm b/private/crt32/misc/i386/setjmp.asm new file mode 100644 index 000000000..f4015572e --- /dev/null +++ b/private/crt32/misc/i386/setjmp.asm @@ -0,0 +1,151 @@ +;*** +;setjmp.asm +; +; Copyright (C) 1993 - 1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Contains setjmp() & raisex() routines; +; split from exsup.asm for granularity purposes. +; +;Notes: +; +;Revision History: +; 04-13-93 JWM Module created. +; 10-14-93 GJF Merged in NT verson. +; 01-12-94 PML Added C9.0 generic EH callback for unwind. Split +; into setjmp.asm, setjmp3.asm, and longjmp.asm. +; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not +; 0. +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +assumes DS,DATA +assumes FS,DATA + +BeginCODE +if @Version LT 600 +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +endif + +; Following symbol defined in exsup.asm +extrn __except_list:near + +; int +; _setjmp ( +; OUT jmp_buf env) +; +; Routine Description: +; +; (Old) implementation of setjmp intrinsic. Saves the current +; nonvolatile register state in the specified jump buffer and returns +; a function value of zero. +; +; Saves the callee-save registers, stack pointer and return address. +; Also saves the exception registration list head. +; +; This code is only present for old apps that link to the DLL runtimes, +; or old object files compiles with C8.0. It intentionally duplicates +; the old setjmp bugs, blindly assuming that the topmost EH node is a +; C8.0 SEH node. +; +; Arguments: +; +; env - Address of the buffer for storing the state information +; +; Return Value: +; +; A value of zero is returned. + +public __setjmp +__setjmp PROC NEAR + mov edx, [esp+4] + mov [edx.saved_ebp], ebp ; old bp and the rest + mov [edx.saved_ebx], ebx + mov [edx.saved_edi], edi + mov [edx.saved_esi], esi + mov [edx.saved_esp], esp + + mov eax, [esp] ; return address + mov [edx.saved_return], eax + + mov eax, dword ptr fs:__except_list + mov [edx.saved_xregistration], eax + + cmp eax, -1 ; -1 means no higher-level handler + jnz short _sj_save_trylevel + mov dword ptr [edx.saved_trylevel], -1 ;something invalid + jmp short _sj_done + +_sj_save_trylevel: + mov eax, [eax + C8_TRYLEVEL] + mov [edx.saved_trylevel], eax + +_sj_done: + sub eax, eax + ret +__setjmp ENDP + +; void +; raisex ( +; IN PEXCEPTION_RECORD pxr) +; +; Routine Description: +; +; Unknown. This seems to duplicate the RaiseException API (sort of), +; but I'm not sure what it's doing here. It's not documented, but +; it's in the reserved ANSI namespace. Here it stays, in case someone +; really counts on it. +; +; Arguments: +; +; pxr - Pointer to EXCEPTION_RECORD buffer +; +; Return Value: +; +; None. + +cProc raisex,<C,PUBLIC> + parmDP pxr +cBegin + pushfd + pushad + + mov esi, dword ptr pxr + mov ebx, dword ptr fs:__except_list +_r_top: + or ebx, ebx + je short _r_error + push ebx ;pass address of the registration record + push esi ;pass the exception record + call [ebx.handler] ;execute language handler for this proc + add esp, 8 + cmp eax, DISPOSITION_DISMISS + je short _r_dismiss + cmp eax, DISPOSITION_CONTINUE_SEARCH + jne short _r_error + mov ebx, [ebx.prev] + jmp short _r_top +_r_error: + ;assert(UNREACHED); exit(-1); +_r_dismiss: + popad + popfd +cEnd + +EndCODE +END diff --git a/private/crt32/misc/i386/setjmp3.asm b/private/crt32/misc/i386/setjmp3.asm new file mode 100644 index 000000000..9c03e9a8c --- /dev/null +++ b/private/crt32/misc/i386/setjmp3.asm @@ -0,0 +1,148 @@ +;*** +;setjmp3.asm +; +; Copyright (C) 1994 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Contains setjmp(), longjmp() & raisex() routines; +; split from exsup.asm for granularity purposes. +; +;Notes: +; +;Revision History: +; 01-12-94 PML Split from setjmp.asm, added C9.0 generic EH +; callback for unwind. +; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not +; 0. +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +include exsup.inc +.list + +assumes DS,DATA +assumes FS,DATA + +BeginCODE +if @Version LT 600 +;this needs to go here to work around a masm5 bug. (emits wrong fixup) +assumes CS,FLAT +endif + +; Following symbol defined in exsup.asm +extrn __except_list:near + +; int +; _setjmp3 ( +; OUT jmp_buf env, +; int count, +; ...) +; +; Routine Description: +; +; (New) implementation of setjmp intrinsic. Saves the current +; nonvolatile register state in the specified jump buffer and returns +; a function value of zero. +; +; Saves the callee-save registers, stack pointer and return address. +; Also saves the exception registration list head. If setjmp is +; called from a function using any form of exception handling, then +; additional data is also saved allowing some form of local unwind +; at longjmp time to restore the proper exception handling state. +; +; Arguments: +; +; env - Address of the buffer for storing the state information +; count - count of additional DWORDs of information. Zero if setjmp +; not called from a function with any form of EH. +; ... Additional data pushed by the setjmp intrinsic if called +; from a function with any form of EH. The first DWORD is +; a function ptr which will be called at longjmp time to do +; the local unwind. The second DWORD is the try level to be +; restored (if applicable). Any further data is saved in the +; generic data array in the jmp_buf for use by the local +; unwind function. +; +; Return Value: +; +; A value of zero is returned. + +public __setjmp3 +__setjmp3 PROC NEAR + mov edx, [esp+4] + mov [edx.saved_ebp], ebp ; old bp and the rest + mov [edx.saved_ebx], ebx + mov [edx.saved_edi], edi + mov [edx.saved_esi], esi + mov [edx.saved_esp], esp + + mov eax, [esp] ; return address + mov [edx.saved_return], eax + + mov dword ptr [edx.version_cookie], JMPBUF_COOKIE + mov dword ptr [edx.unwind_func], 0 + + mov eax, dword ptr fs:__except_list + mov [edx.saved_xregistration], eax + + cmp eax, -1 ; -1 means no higher-level handler + jnz short _s3_get_count + mov dword ptr [edx.saved_trylevel], -1 ;something invalid + jmp short _s3_done + +_s3_get_count: + mov ecx, [esp+8] ; count of additional data + or ecx, ecx + jz short _s3_default_trylevel + + mov eax, [esp+12] ; func to do local unwind at longjmp + mov [edx.unwind_func], eax + dec ecx + jnz _s3_save_trylevel + + ; Not called from a function with any form of EH, or no trylevel + ; passed. Save the TryLevel from the topmost EH node anyway, + ; assuming a C8.0 SEH node. If we're linked to an obsolete CRTDLL + ; and call the old longjmp, then we'll still do the right thing. +_s3_default_trylevel: + mov eax, [eax + C8_TRYLEVEL] + mov [edx.saved_trylevel], eax + jmp short _s3_done + +_s3_save_trylevel: + mov eax, [esp+16] ; try level to unwind to + mov [edx.saved_trylevel], eax + dec ecx + jz short _s3_done + + push esi + push edi + lea esi, [esp+20+8] + lea edi, [edx.unwind_data] + cmp ecx, 6 ; save up to 6 more DWORDs in jmp_buf + jbe _s3_save_data + mov ecx, 6 + +_s3_save_data: + rep movsd + pop edi + pop esi + +_s3_done: + sub eax, eax + ret +__setjmp3 ENDP + +EndCODE +END diff --git a/private/crt32/misc/i386/setjmpex.asm b/private/crt32/misc/i386/setjmpex.asm new file mode 100644 index 000000000..dfe444b7c --- /dev/null +++ b/private/crt32/misc/i386/setjmpex.asm @@ -0,0 +1,55 @@ +;*** +;setjmpex.asm +; +; Copyright (c) 1993 Microsoft Corporation. All rights reserved. +; +;Purpose: +; Contains setjmpex(). +; +;Notes: +; +;Revision History: +; 10-14-93 GJF Grabbed from NT SDK tree, cleaned up a bit and this +; header was added. +; 01-13-94 PML Trigger off __longjmpex instead of __setjmpex, since +; _setjmp is an intrinsic, but longjmp isn't. +; +;******************************************************************************* + +;hnt = -D_WIN32_ -Dsmall32 -Dflat32 -Mx $this; + +;Define small32 and flat32 since these are not defined in the NT build process +small32 equ 1 +flat32 equ 1 + +.xlist +include pversion.inc +?DFDATA = 1 +?NODATA = 1 +include cmacros.mas +.list + + +extrn _longjmp:near + +; +; If setjmpex is included then set __setjmpexused = 1. +; + +BeginDATA + public __setjmpexused +__setjmpexused dd 1 +EndDATA + +BeginCODE +if @Version LT 600 +assumes CS,FLAT +endif + +public __longjmpex +__longjmpex PROC NEAR + jmp _longjmp +__longjmpex ENDP + +EndCODE +END diff --git a/private/crt32/misc/initcoll.c b/private/crt32/misc/initcoll.c new file mode 100644 index 000000000..d2e2985a7 --- /dev/null +++ b/private/crt32/misc/initcoll.c @@ -0,0 +1,51 @@ +/*** +*initcoll.c - contains _init_collate +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the locale-category initialization function: _init_collate(). +* +* Each initialization function sets up locale-specific information +* for their category, for use by functions which are affected by +* their locale category. +* +* *** For internal use by setlocale() only *** +* +*Revision History: +* 12-08-91 ETC Created. +* 12-20-91 ETC Minor beautification for consistency. +* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3. +* 05-20-93 GJF Include windows.h, not individual win*.h files +* +*******************************************************************************/ + +#ifdef _INTL +#include <windows.h> +#include <locale.h> +#include <setlocal.h> + +/*** +*int _init_collate() - initialization for LC_COLLATE locale category. +* +*Purpose: +* The LC_COLLATE category currently requires no initialization. +* +*Entry: +* None. +* +*Exit: +* 0 success +* 1 fail +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI3 _init_collate ( + void + ) +{ + return 0; +} +#endif /* _INTL */ diff --git a/private/crt32/misc/initctyp.c b/private/crt32/misc/initctyp.c new file mode 100644 index 000000000..02382a1b2 --- /dev/null +++ b/private/crt32/misc/initctyp.c @@ -0,0 +1,212 @@ +/*** +*initctyp.c - contains _init_ctype +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the locale-category initialization function: _init_ctype(). +* +* Each initialization function sets up locale-specific information +* for their category, for use by functions which are affected by +* their locale category. +* +* *** For internal use by setlocale() only *** +* +*Revision History: +* 12-08-91 ETC Created. +* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo. +* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3. +* 01-19-03 CFW Move to _NEWCTYPETABLE, remove switch. +* 02-08-93 CFW Bug fixes under _INTL switch. +* 05-20-93 GJF Include windows.h, not individual win*.h files +* 06-11-93 CFW Now inithelp takes void *. +* +*******************************************************************************/ + +#ifdef _INTL + +#include <stdlib.h> +#include <windows.h> +#include <locale.h> +#include <setlocal.h> +#include <ctype.h> +#include <malloc.h> +#include <limits.h> + +#define _CTABSIZE 257 /* size of ctype tables */ + +/*** +*int _init_ctype() - initialization for LC_CTYPE locale category. +* +*Purpose: +* In non-C locales, preread ctype tables for chars and wide-chars. +* Old tables are freed when new tables are fully established, else +* the old tables remain intact (as if original state unaltered). +* The leadbyte table is implemented as the high bit in ctype1. +* +* In the C locale, ctype tables are freed, and pointers point to +* the static ctype table. +* +* Tables contain 257 entries: -1 to 256. +* Table pointers point to entry 0 (to allow index -1). +* +*Entry: +* None. +* +*Exit: +* 0 success +* 1 fail +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI3 _init_ctype ( + void + ) +{ +#if defined _POSIX_ + return 0; + +#else /* _POSIX_ */ + /* non-C locale table for char's */ + static unsigned short *ctype1 = NULL; /* keep around until next time */ + unsigned short *newctype1; /* temp new table */ + + /* non-C locale table for wchar_t's */ + static unsigned short *wctype1 = NULL; /* keep around until next time */ + unsigned short *newwctype1; /* temp new table */ + + int size; // char buffer sizes + int wcsize; // wide char buffer sizes + unsigned char *cbuffer = NULL; // char working buffer + wchar_t *wbuffer = NULL; // wchar_t working buffer + + int i; // general purpose counter + unsigned char *cp; // char pointer + wchar_t *wcp; // wide char pointer + CPINFO CPInfo; // struct for use with GetCPInfo + + /* allocate and set up buffers before destroying old ones */ + /* codepage will be restored by setlocale if error */ + + if (_lc_handle[LC_CTYPE] != _CLOCALEHANDLE) + { + if (_lc_codepage == 0) + { /* code page was not specified */ + if (_getlocaleinfo(LC_INT_TYPE, MAKELCID(_lc_id[LC_CTYPE].wLanguage, SORT_DEFAULT), + LOCALE_IDEFAULTCODEPAGE, + (void *)&_lc_codepage) == -1) + goto error_cleanup; + } + + /* allocate new buffers for tables */ + newctype1 = (unsigned short *) malloc + (_CTABSIZE * sizeof(unsigned short)); + newwctype1 = (unsigned short *) malloc + (_CTABSIZE * sizeof(unsigned short)); + cbuffer = (unsigned char *) malloc (_CTABSIZE * sizeof(char)); + wbuffer = (wchar_t *) malloc (_CTABSIZE * sizeof(wchar_t)); + + if (!newctype1 || !newwctype1 || !cbuffer || !wbuffer) + goto error_cleanup; + + /* construct string composed of first 256 chars in sequence */ + for (cp=cbuffer, i=0; i<_CTABSIZE-1; i++) + *cp++ = (unsigned char)i; + + if (GetCPInfo( _lc_codepage, &CPInfo) == FALSE) + goto error_cleanup; + + if (CPInfo.MaxCharSize > MB_LEN_MAX) + goto error_cleanup; + + __mb_cur_max = (unsigned short) CPInfo.MaxCharSize; + + /* zero out leadbytes so MBtoWC doesn't interpret as multi-byte chars */ + if (__mb_cur_max > 1) + { + for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2) + { + for (i = cp[0]; i <= cp[1]; i++) + cbuffer[i] = 0; + } + } + + /* convert to wide character string */ + size = (_CTABSIZE-1) * sizeof(char); + wcsize = (_CTABSIZE-1) * sizeof(wchar_t); + if (MultiByteToWideChar (_lc_codepage, 0, (char *)cbuffer, size, + wbuffer, wcsize) == 0) + goto error_cleanup; + + /* convert to newctype1 table */ + if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newctype1+1) + == FALSE) + goto error_cleanup; + *newctype1 = 0; /* entry for EOF */ + + /* construct wide char string composed of first 256 chars in sequence */ + for (wcp=wbuffer, i=0; i<_CTABSIZE-1; i++) + *wcp++ = (wchar_t)i; + + /* convert to newctype1 table */ + if (GetStringTypeW (CT_CTYPE1, wbuffer, _CTABSIZE-1, newwctype1+1) + == FALSE) + goto error_cleanup; + *newwctype1 = 0; /* entry for EOF */ + + /* ignore DefaultChar */ + + /* mark lead-byte entries in newctype1 table */ + if (__mb_cur_max > 1) + { + for (cp = (unsigned char *)CPInfo.LeadByte; cp[0] && cp[1]; cp += 2) + { + for (i = cp[0]; i <= cp[1]; i++) + newctype1[i+1] = _LEADBYTE; + } + } + + /* set pointers to point to entry 0 of tables */ + _pctype = newctype1 + 1; + _pwctype = newwctype1 + 1; + + /* free old tables */ + if (ctype1) + free (ctype1); + ctype1 = newctype1; + + if (wctype1) + free (wctype1); + wctype1 = newwctype1; + + /* cleanup and return success */ + free (cbuffer); + free (wbuffer); + return 0; + +error_cleanup: + free (newctype1); + free (newwctype1); + free (cbuffer); + free (wbuffer); + return 1; + + } else { + + /* set pointers to static C-locale table */ + _pctype = _ctype + 1; + _pwctype = _ctype + 1; + + /* free dynamic locale-specific tables */ + free (ctype1); + free (wctype1); + ctype1 = NULL; + wctype1 = NULL; + + return 0; + } +#endif /* _POSIX_ */ +} +#endif /* _INTL */ diff --git a/private/crt32/misc/inithelp.c b/private/crt32/misc/inithelp.c new file mode 100644 index 000000000..a372b595a --- /dev/null +++ b/private/crt32/misc/inithelp.c @@ -0,0 +1,143 @@ +/*** +*inithelp.c - Contains the _getlocaleinfo helper routine +* +* Copyright (c) 1992-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the _getlocaleinfo helper routine. +* +*Revision History: +* 12-28-92 CFW Module created, _getlocaleinfo ported to Cuda tree. +* 12-29-92 CFW Update for new GetLocaleInfoW, add LC_*_TYPE handling. +* 01-25-93 KRS Change category argument to LCID. +* 02-02-93 CFW Optimized INT case, bug fix in STR case. +* 02-08-93 CFW Optimized GetQualifiedLocale call, cast to remove warnings. +* 04-22-93 CFW Fixed cast bug. +* 06-11-93 CFW Now inithelp takes void *, use wcstod(). +* +*******************************************************************************/ + +#ifdef _INTL + +#include <stdlib.h> +#include <cruntime.h> +#include <locale.h> +#include <setlocal.h> + +/*** +*_getlocaleinfo - return locale data +* +*Purpose: +* Return locale data appropriate for the setlocale init functions. +* In particular, wide locale strings are converted to char strings +* or numeric depending on the value of the first parameter. +* +* Memory is allocated for the char version of the data, and the +* calling function's pointer is set to it. This pointer should later +* be used to free the data. The wide-char data is fetched using +* GetLocaleInfo and converted to multibyte using WideCharToMultiByte. +* +* *** For internal use by the _init_* functions only *** +* +* *** Future optimization *** +* When converting a large number of wide-strings to multibyte, do +* not query the size of the result, but convert them one after +* another into a large character buffer. The entire buffer can +* also be freed with one pointer. +* +*Entry: +* int lc_type - LC_STR_TYPE for string data, LC_INT_TYPE for numeric data +* LCID localehandle - LCID based on category and lang or ctry of _lc_id + LCTYPE fieldtype - int or string value +* +*Exit: +* void *address - pointer to pointer to storage +* 0 success +* -1 failure +* +*Exceptions: +* +*******************************************************************************/ + +#if NO_ERROR == -1 +#error Need to use another error return code in _getlocaleinfo +#endif + +#define STR_CHAR_CNT 128 +#define INT_CHAR_CNT 4 + +int _CRTAPI3 _getlocaleinfo ( + int lc_type, + LCID localehandle, + LCTYPE fieldtype, + void *address + ) +{ +#if defined _POSIX_ + return -1; +#else /* _POSIX_ */ + if (lc_type == LC_STR_TYPE) + { + char **straddress = (char **)address; + + static wchar_t staticwcbuffer[STR_CHAR_CNT]; + wchar_t *wcbuffer = staticwcbuffer; + int bufferused = 0; /* 1 indicates buffer points to malloc'ed memory */ + int buffersize = STR_CHAR_CNT * sizeof(wchar_t); + int outsize; + + if (GetLocaleInfoW (localehandle, fieldtype, wcbuffer, buffersize) == 0) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto error; + /* buffersize too small, get required size and malloc new buffer */ + if ((buffersize = GetLocaleInfoW (localehandle, fieldtype, NULL, 0)) + == 0) + goto error; + if ((wcbuffer = (wchar_t *) malloc (buffersize)) == NULL) + goto error; + bufferused = 1; + if (GetLocaleInfoW (localehandle, fieldtype, wcbuffer, buffersize) == 0) + goto error; + } + + if ((outsize = WideCharToMultiByte (_lc_codepage, 0, wcbuffer, -1, + NULL, 0, NULL, NULL)) == 0) + goto error; + + if ((*straddress = (char *) malloc (outsize)) == NULL) + goto error; + + if (WideCharToMultiByte (_lc_codepage, 0, wcbuffer, -1, + *straddress, outsize, NULL, NULL) == 0) + goto error; + + if (bufferused) + free (wcbuffer); + + return 0; + +error: + if (bufferused) + free (wcbuffer); + return -1; + + } else if (lc_type == LC_INT_TYPE) + { + char *charaddress = (char *)address; + wchar_t wcbuffer[INT_CHAR_CNT]; + + if (GetLocaleInfoW (localehandle, fieldtype, (LPWSTR)wcbuffer, INT_CHAR_CNT) == 0) + return -1; + + /* GetLocaleInfoW returns integer in wcstr format */ + + *(char *)charaddress = (char)wcstol(wcbuffer, NULL, 10); + + return 0; + } + return -1; +#endif /* _POSIX_ */ +} + +#endif /*_INTL*/ diff --git a/private/crt32/misc/initmon.c b/private/crt32/misc/initmon.c new file mode 100644 index 000000000..c2b9cd3fe --- /dev/null +++ b/private/crt32/misc/initmon.c @@ -0,0 +1,191 @@ +/*** +*initmon.c - contains _init_monetary +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the locale-category initialization function: _init_monetary(). +* +* Each initialization function sets up locale-specific information +* for their category, for use by functions which are affected by +* their locale category. +* +* *** For internal use by setlocale() only *** +* +*Revision History: +* 12-08-91 ETC Created. +* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo. +* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3. +* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function. +* 01-25-93 KRS Changed _getlocaleinfo interface again. +* 02-08-93 CFW Added _lconv_static_*. +* 02-17-93 CFW Removed debugging print statement. +* 05-20-93 GJF Include windows.h, not individual win*.h files +* 06-11-93 CFW Now inithelp takes void *. +* +*******************************************************************************/ + +#ifdef _INTL + +#include <stdlib.h> +#include <windows.h> +#include <locale.h> +#include <setlocal.h> +#include <malloc.h> +#include <limits.h> + +static int _CRTAPI3 _get_lc_lconv(struct lconv *l); +static void _CRTAPI3 _free_lc_lconv(struct lconv *l); + +/* Pointer to current lconv */ +extern struct lconv *_lconv; + +/* C locale lconv structure */ +extern struct lconv _lconv_c; + +/* Pointer to non-C locale lconv */ +static struct lconv *_lconv_intl = NULL; + +/* + * Note that _lconv_c is used when the monetary category is in the C locale + * but the numeric category may not necessarily be in the C locale. + */ + + +/*** +*int _init_monetary() - initialization for LC_MONETARY locale category. +* +*Purpose: +* In non-C locales, read the localized monetary strings into +* _lconv_intl, and also copy the numeric strings from _lconv into +* _lconv_intl. Set _lconv to point to _lconv_intl. The old +* _lconv_intl is not freed until the new one is fully established. +* +* In the C locale, the monetary fields in lconv are filled with +* contain C locale values. Any allocated _lconv_intl fields are freed. +* +* At startup, _lconv points to a static lconv structure containing +* C locale strings. This structure is never used again if +* _init_monetary is called. +* +*Entry: +* None. +* +*Exit: +* 0 success +* 1 fail +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI3 _init_monetary ( + void + ) +{ + struct lconv *lc; + + if (_lc_handle[LC_MONETARY] != _CLOCALEHANDLE) { + + /* Allocate structure filled with NULL pointers */ + if ((lc = (struct lconv *) + calloc (1, sizeof(struct lconv))) == NULL) + return 1; + + if (_get_lc_lconv (lc) == -1) { + _free_lc_lconv (lc); + free ((void *)lc); + return 1; + } + + /* Copy numeric locale fields */ + lc->decimal_point = _lconv->decimal_point; + lc->thousands_sep = _lconv->thousands_sep; + lc->grouping = _lconv->grouping; + + _lconv = lc; /* point to new one */ + _free_lc_lconv (_lconv_intl); /* free the old one */ + free ((void *)_lconv_intl); + _lconv_intl = lc; + return 0; + + } else { + /* + * Copy numeric locale fields (not necessarily C locale) + * to static structure. Note that _lconv_c numeric locale + * fields may contain non-C locale information, but + * monetary locale fields always contain C locale info. + */ + _lconv_c.decimal_point = _lconv->decimal_point; + _lconv_c.thousands_sep = _lconv->thousands_sep; + _lconv_c.grouping = _lconv->grouping; + + _lconv = &_lconv_c; /* point to new one */ + + _free_lc_lconv (_lconv_intl); /* free the old one */ + free ((void *)_lconv_intl); + _lconv_intl = NULL; + return 0; + } +} + +/* + * Get the lconv fields. + */ +static int _CRTAPI3 _get_lc_lconv ( + struct lconv *l + ) +{ + int ret = 0; + + /* Currency is country--not language--dependent. NT work-around. */ + LCID ctryid=MAKELCID(_lc_id[LC_MONETARY].wCountry, SORT_DEFAULT); + + if (l == NULL) + return -1; + + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SINTLSYMBOL, (void *)&l->int_curr_symbol); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SCURRENCY, (void *)&l->currency_symbol); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONDECIMALSEP, (void *)&l->mon_decimal_point); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONTHOUSANDSEP, (void *)&l->mon_thousands_sep); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SMONGROUPING, (void *)&l->mon_grouping); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SPOSITIVESIGN, (void *)&l->positive_sign); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SNEGATIVESIGN, (void *)&l->negative_sign); + + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IINTLCURRDIGITS, (void *)&l->int_frac_digits); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ICURRDIGITS, (void *)&l->frac_digits); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSYMPRECEDES, (void *)&l->p_cs_precedes); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSEPBYSPACE, (void *)&l->p_sep_by_space); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSYMPRECEDES, (void *)&l->n_cs_precedes); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSEPBYSPACE, (void *)&l->n_sep_by_space); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_IPOSSIGNPOSN, (void *)&l->p_sign_posn); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_INEGSIGNPOSN, (void *)&l->n_sign_posn); + + return ret; +} + +/* + * Free the lconv strings. + * Numeric values do not need to be freed. + */ +static void _CRTAPI3 _free_lc_lconv ( + struct lconv *l + ) +{ + if (l == NULL) + return; + + if (l->int_curr_symbol != _lconv_static_null) + { + free (l->int_curr_symbol); + free (l->currency_symbol); + free (l->mon_decimal_point); + free (l->mon_thousands_sep); + free (l->mon_grouping); + free (l->positive_sign); + free (l->negative_sign); + } + /* Don't need to make these pointers NULL */ +} + +#endif /* _INTL */ diff --git a/private/crt32/misc/initnum.c b/private/crt32/misc/initnum.c new file mode 100644 index 000000000..dea832aad --- /dev/null +++ b/private/crt32/misc/initnum.c @@ -0,0 +1,129 @@ +/*** +*initnum.c - contains _init_numeric +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the locale-category initialization function: _init_numeric(). +* +* Each initialization function sets up locale-specific information +* for their category, for use by functions which are affected by +* their locale category. +* +* *** For internal use by setlocale() only *** +* +*Revision History: +* 12-08-91 ETC Created. +* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo. +* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3. +* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function. +* 01-25-93 KRS Change interface to _getlocaleinfo again. +* 02-08-93 CFW Added _lconv_static_*. +* 02-17-93 CFW Removed debugging print statement. +* 03-17-93 CFW C locale thousands sep is "", not ",". +* 05-20-93 GJF Include windows.h, not individual win*.h files +* 06-11-93 CFW Now inithelp takes void *. +* +*******************************************************************************/ + +#ifdef _INTL + +#include <stdlib.h> +#include <string.h> +#include <windows.h> +#include <locale.h> +#include <setlocal.h> +#include <malloc.h> +#include <assert.h> +#include <nlsint.h> + +/* Pointer to current lconv */ +extern struct lconv *_lconv; + +/*** +*int _init_numeric() - initialization for LC_NUMERIC locale category. +* +*Purpose: +* +*Entry: +* None. +* +*Exit: +* 0 success +* 1 fail +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI3 _init_numeric ( + void + ) +{ + static char *decimal_point = NULL; + static char *thousands_sep = NULL; + static char *grouping = NULL; + int ret = 0; + + /* Numeric data is country--not language--dependent. NT work-around. */ + LCID ctryid = MAKELCID(_lc_id[LC_NUMERIC].wCountry, SORT_DEFAULT); + + if (_lc_handle[LC_NUMERIC] != _CLOCALEHANDLE) + { + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SDECIMAL, (void *)&decimal_point); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_STHOUSAND, (void *)&thousands_sep); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SGROUPING, (void *)&grouping); + + if (ret == -1) + { + free (decimal_point); + free (thousands_sep); + free (grouping); + decimal_point = NULL; + thousands_sep = NULL; + grouping = NULL; + return -1; + } + + if (_lconv->decimal_point != _lconv_static_decimal) + { + free(_lconv->decimal_point); + free(_lconv->thousands_sep); + free(_lconv->grouping); + } + + _lconv->decimal_point = decimal_point; + _lconv->thousands_sep = thousands_sep; + _lconv->grouping = grouping; + + +#ifdef _DEBUG + assert (strlen(_lconv->decimal_point) == 1); +#endif + /* set global decimal point character */ + *_decimal_point = *_lconv->decimal_point; + _decimal_point_length = 1; + + return 0; + + } else { + free (decimal_point); + free (thousands_sep); + free (grouping); + decimal_point = NULL; + thousands_sep = NULL; + grouping = NULL; + + // strdup them so we can free them + _lconv->decimal_point = _strdup("."); + _lconv->thousands_sep = _strdup(""); + _lconv->grouping = strdup(""); + + /* set global decimal point character */ + *_decimal_point = *_lconv->decimal_point; + _decimal_point_length = 1; + + return 0; + } +} +#endif /* _INTL */ diff --git a/private/crt32/misc/inittime.c b/private/crt32/misc/inittime.c new file mode 100644 index 000000000..7ce1dd8e7 --- /dev/null +++ b/private/crt32/misc/inittime.c @@ -0,0 +1,301 @@ +/*** +*inittime.c - contains _init_time +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the locale-category initialization function: _init_time(). +* +* Each initialization function sets up locale-specific information +* for their category, for use by functions which are affected by +* their locale category. +* +* *** For internal use by setlocale() only *** +* +*Revision History: +* 12-08-91 ETC Created. +* 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo. +* 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3. +* 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function. +* 01-25-93 KRS Adapted to use ctry or lang dependent data, as approp. +* 02-08-93 CFW Casts to remove warnings. +* 02-16-93 CFW Added support for date and time strings. +* 03-09-93 CFW Use char* time_sep in storeTimeFmt. +* 05-20-93 GJF Include windows.h, not individual win*.h files +* 06-11-93 CFW Now inithelp takes void *. +* +*******************************************************************************/ + +#ifdef _INTL + +#include <stdlib.h> +#include <windows.h> +#include <locale.h> +#include <setlocal.h> +#include <malloc.h> + +static int _CRTAPI3 _get_lc_time(struct _lc_time_data *lc_time); +static void _CRTAPI3 _free_lc_time(struct _lc_time_data *lc_time); + +/* Pointer to current time strings */ +extern struct _lc_time_data *_lc_time_curr; + +/* C locale time strings */ +extern struct _lc_time_data _lc_time_c; + +/* Pointer to non-C locale time strings */ +struct _lc_time_data *_lc_time_intl = NULL; + +int storeTimeFmt( + int ctryid, + struct _lc_time_data *lc_time +); + +/*** +*int _init_time() - initialization for LC_TIME locale category. +* +*Purpose: +* In non-C locales, read the localized time/date strings into +* _lc_time_intl, and set _lc_time_curr to point to it. The old +* _lc_time_intl is not freed until the new one is fully established. +* +* In the C locale, _lc_time_curr is made to point to _lc_time_c. +* Any allocated _lc_time_intl structures are freed. +* +*Entry: +* None. +* +*Exit: +* 0 success +* 1 fail +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI3 _init_time ( + void + ) +{ + /* Temporary date/time strings */ + struct _lc_time_data *lc_time; + + if (_lc_handle[LC_TIME] != _CLOCALEHANDLE) + { + /* Allocate structure filled with NULL pointers */ + if ((lc_time = (struct _lc_time_data *) + calloc (1, sizeof(struct _lc_time_data))) == NULL) + return 1; + + if (_get_lc_time (lc_time)) + { + _free_lc_time (lc_time); + free ((void *)lc_time); + return 1; + } + + _lc_time_curr = lc_time; /* point to new one */ + _free_lc_time (_lc_time_intl); /* free the old one */ + free ((void *)_lc_time_intl); + _lc_time_intl = lc_time; + return 0; + + } else { + _lc_time_curr = &_lc_time_c; /* point to new one */ + _free_lc_time (_lc_time_intl); /* free the old one */ + free ((void *)_lc_time_intl); + _lc_time_intl = NULL; + return 0; + } +} + +/* + * Get the localized time strings. + * Of course, this can be beautified with some loops! + */ +static int _CRTAPI3 _get_lc_time ( + struct _lc_time_data *lc_time + ) +{ + int ret = 0; + +/* Some things are language-dependent and some are country-dependent. + This works around an NT limitation and lets us distinguish the two. */ + + LCID langid = MAKELCID(_lc_id[LC_TIME].wLanguage, SORT_DEFAULT); + LCID ctryid = MAKELCID(_lc_id[LC_TIME].wCountry, SORT_DEFAULT); + + if (lc_time == NULL) + return -1; + +/* All the text-strings are Language-dependent: */ + + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME1, (void *)&lc_time->wday_abbr[1]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME2, (void *)&lc_time->wday_abbr[2]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME3, (void *)&lc_time->wday_abbr[3]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME4, (void *)&lc_time->wday_abbr[4]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME5, (void *)&lc_time->wday_abbr[5]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME6, (void *)&lc_time->wday_abbr[6]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVDAYNAME7, (void *)&lc_time->wday_abbr[0]); + + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME1, (void *)&lc_time->wday[1]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME2, (void *)&lc_time->wday[2]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME3, (void *)&lc_time->wday[3]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME4, (void *)&lc_time->wday[4]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME5, (void *)&lc_time->wday[5]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME6, (void *)&lc_time->wday[6]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SDAYNAME7, (void *)&lc_time->wday[0]); + + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME1, (void *)&lc_time->month_abbr[0]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME2, (void *)&lc_time->month_abbr[1]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME3, (void *)&lc_time->month_abbr[2]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME4, (void *)&lc_time->month_abbr[3]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME5, (void *)&lc_time->month_abbr[4]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME6, (void *)&lc_time->month_abbr[5]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME7, (void *)&lc_time->month_abbr[6]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME8, (void *)&lc_time->month_abbr[7]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME9, (void *)&lc_time->month_abbr[8]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME10, (void *)&lc_time->month_abbr[9]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME11, (void *)&lc_time->month_abbr[10]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SABBREVMONTHNAME12, (void *)&lc_time->month_abbr[11]); + + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME1, (void *)&lc_time->month[0]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME2, (void *)&lc_time->month[1]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME3, (void *)&lc_time->month[2]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME4, (void *)&lc_time->month[3]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME5, (void *)&lc_time->month[4]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME6, (void *)&lc_time->month[5]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME7, (void *)&lc_time->month[6]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME8, (void *)&lc_time->month[7]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME9, (void *)&lc_time->month[8]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME10, (void *)&lc_time->month[9]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME11, (void *)&lc_time->month[10]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_SMONTHNAME12, (void *)&lc_time->month[11]); + + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_S1159, (void *)&lc_time->ampm[0]); + ret |= _getlocaleinfo(LC_STR_TYPE, langid, LOCALE_S2359, (void *)&lc_time->ampm[1]); + + +/* The following relate to time format and are Country-dependent: */ + + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SSHORTDATE, (void *)&lc_time->ww_sdatefmt); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SLONGDATE, (void *)&lc_time->ww_ldatefmt); + +/* NLS API dropped time format strings, we have to make up our own */ + ret |= storeTimeFmt(ctryid, lc_time); + + return ret; +} + +/* + * Free the localized time strings. + * Of course, this can be beautified with some loops! + */ +static void _CRTAPI3 _free_lc_time ( + struct _lc_time_data *lc_time + ) +{ + if (lc_time == NULL) + return; + + free ((void *)lc_time->wday_abbr[1]); + free ((void *)lc_time->wday_abbr[2]); + free ((void *)lc_time->wday_abbr[3]); + free ((void *)lc_time->wday_abbr[4]); + free ((void *)lc_time->wday_abbr[5]); + free ((void *)lc_time->wday_abbr[6]); + free ((void *)lc_time->wday_abbr[0]); + + free ((void *)lc_time->wday[1]); + free ((void *)lc_time->wday[2]); + free ((void *)lc_time->wday[3]); + free ((void *)lc_time->wday[4]); + free ((void *)lc_time->wday[5]); + free ((void *)lc_time->wday[6]); + free ((void *)lc_time->wday[0]); + + free ((void *)lc_time->month_abbr[0]); + free ((void *)lc_time->month_abbr[1]); + free ((void *)lc_time->month_abbr[2]); + free ((void *)lc_time->month_abbr[3]); + free ((void *)lc_time->month_abbr[4]); + free ((void *)lc_time->month_abbr[5]); + free ((void *)lc_time->month_abbr[6]); + free ((void *)lc_time->month_abbr[7]); + free ((void *)lc_time->month_abbr[8]); + free ((void *)lc_time->month_abbr[9]); + free ((void *)lc_time->month_abbr[10]); + free ((void *)lc_time->month_abbr[11]); + + free ((void *)lc_time->month[0]); + free ((void *)lc_time->month[1]); + free ((void *)lc_time->month[2]); + free ((void *)lc_time->month[3]); + free ((void *)lc_time->month[4]); + free ((void *)lc_time->month[5]); + free ((void *)lc_time->month[6]); + free ((void *)lc_time->month[7]); + free ((void *)lc_time->month[8]); + free ((void *)lc_time->month[9]); + free ((void *)lc_time->month[10]); + free ((void *)lc_time->month[11]); + + free ((void *)lc_time->ampm[0]); + free ((void *)lc_time->ampm[1]); + + free ((void *)lc_time->ww_sdatefmt); + free ((void *)lc_time->ww_ldatefmt); + free ((void *)lc_time->ww_timefmt); +/* Don't need to make these pointers NULL */ +} + + +/* NLS API dropped time format strings, we have to make up our own */ +int storeTimeFmt( + int ctryid, + struct _lc_time_data *lc_time +) +{ + int ret = 0; + char *pfmt, *psep; + char *time_sep; + unsigned clock24 = 0; + unsigned leadzero = 0; + + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ITIME, (void *)&clock24); + ret |= _getlocaleinfo(LC_INT_TYPE, ctryid, LOCALE_ITLZERO, (void *)&leadzero); + ret |= _getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_STIME, (void *)&time_sep); + + if (ret) + return ret; + + /* 13 = 6 chars for hhmmss + up to three for each separator + NULL */ + + pfmt = lc_time->ww_timefmt = (char *)malloc(13); + + if (clock24) + { + *pfmt++ = 'H'; + if (leadzero) + *pfmt++ = 'H'; + } + else { + *pfmt++ = 'h'; + if (leadzero) + *pfmt++ = 'h'; + } + for(psep = time_sep; *psep; *pfmt++ = *psep++) ; + *pfmt++ = 'm'; + if (leadzero) + *pfmt++ = 'm'; + for(psep = time_sep; *psep; *pfmt++ = *psep++) ; + *pfmt++ = 's'; + *pfmt++ = 's'; + *pfmt = '\0'; + + free(time_sep); + + return ret; +} + +#endif /* _INTL */ diff --git a/private/crt32/misc/labs.c b/private/crt32/misc/labs.c new file mode 100644 index 000000000..e26a75115 --- /dev/null +++ b/private/crt32/misc/labs.c @@ -0,0 +1,52 @@ +/*** +*labs.c - find absolute value of a long integer +* +* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines labs() - find absolute value of a long integer. +* +*Revision History: +* 03-15-84 RN initial version +* 04-22-87 JMB added function pragma for conversion to C 5.0 compiler +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 10-04-90 GJF New-style function declarator. +* 12-28-90 SRW Added _CRUISER_ conditional around function pragma +* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too. +* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> + +#ifdef _MSC_VER +#pragma function(labs) +#endif + +/*** +*long labs(lnumber) - find absolute value of long. +* +*Purpose: +* Find the absolute value of a long integer (lnumber if lnumber >= 0), +* -lnumber if lnumber < 0). +* +*Entry: +* long lnumber - number to find absolute value of +* +*Exit: +* returns the absolute value of lnumber +* +*Exceptions: +* +*******************************************************************************/ + +long _CALLTYPE1 labs ( + long lnumber + ) +{ + return( lnumber>=0L ? lnumber : -lnumber ); +} diff --git a/private/crt32/misc/lconv.c b/private/crt32/misc/lconv.c new file mode 100644 index 000000000..a7d18aac6 --- /dev/null +++ b/private/crt32/misc/lconv.c @@ -0,0 +1,86 @@ +/*** +*lconv.c - Contains the localeconv function +* +* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the localeconv() function. +* +*Revision History: +* 03-21-89 JCR Module created. +* 06-20-89 JCR Removed _LOAD_DGROUP code +* 03-14-90 GJF Replaced _cdecl _LOAD_DS with _CALLTYPE1 and added +* #include <cruntime.h>. Also, fixed the copyright. +* 10-04-90 GJF New-style function declarator. +* 10-04-91 ETC Changed _c_lconv to _lconv (locale support). +* _lconv no longer static. +* 12-20-91 ETC Changed _lconv to _lconv_c (C locale structure). +* Created _lconv pointer to point to current lconv. +* 02-08-93 CFW Added _lconv_static_*. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <limits.h> +#include <locale.h> + + + +/* pointer to original static to avoid freeing */ +char _lconv_static_decimal[] = "."; +char _lconv_static_null[] = ""; + +/* lconv settings for "C" locale */ +struct lconv _lconv_c = { + _lconv_static_decimal, /* decimal_point */ + _lconv_static_null, /* thousands_sep */ + _lconv_static_null, /* grouping */ + _lconv_static_null, /* int_curr_symbol */ + _lconv_static_null, /* currency_symbol */ + _lconv_static_null, /* mon_decimal_point */ + _lconv_static_null, /* mon_thousands_sep */ + _lconv_static_null, /* mon_grouping */ + _lconv_static_null, /* positive_sign */ + _lconv_static_null, /* negative_sign */ + CHAR_MAX, /* int_frac_digits */ + CHAR_MAX, /* frac_digits */ + CHAR_MAX, /* p_cs_precedes */ + CHAR_MAX, /* p_sep_by_space */ + CHAR_MAX, /* n_cs_precedes */ + CHAR_MAX, /* n_sep_by_space */ + CHAR_MAX, /* p_sign_posn */ + CHAR_MAX /* n_sign_posn */ + }; + + +/* pointer to current lconv structure */ + +struct lconv *_lconv = &_lconv_c; + + +/*** +*struct lconv *localeconv(void) - Return the numeric formatting convention +* +*Purpose: +* The localeconv() routine returns the numeric formatting conventions +* for the current locale setting. [ANSI] +* +*Entry: +* void +* +*Exit: +* struct lconv * = pointer to struct indicating current numeric +* formatting conventions. +* +*Exceptions: +* +*******************************************************************************/ + +struct lconv * _CALLTYPE1 localeconv ( + void + ) +{ + /* the work is done by setlocale() */ + + return(_lconv); +} diff --git a/private/crt32/misc/ldiv.c b/private/crt32/misc/ldiv.c new file mode 100644 index 000000000..05c92f2da --- /dev/null +++ b/private/crt32/misc/ldiv.c @@ -0,0 +1,59 @@ +/*** +*ldiv.c - contains the ldiv routine +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Performs a signed divide on longs and returns quotient +* and remainder. +* +*Revision History: +* 06-02-89 PHG module created +* 03-14-90 GJF Made calling type _CALLTYPE1 and added #include +* <cruntime.h>. Also, fixed the copyright. +* 10-04-90 GJF New-style function declarator. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> + +/*** +*ldiv_t div(long numer, long denom) - do signed divide +* +*Purpose: +* This routine does an long divide and returns the results. +* Since we don't know how the Intel 860 does division, we'd +* better make sure that we have done it right. +* +*Entry: +* long numer - Numerator passed in on stack +* long denom - Denominator passed in on stack +* +*Exit: +* returns quotient and remainder in structure +* +*Exceptions: +* No validation is done on [denom]* thus, if [denom] is 0, +* this routine will trap. +* +*******************************************************************************/ + +ldiv_t _CALLTYPE1 ldiv ( + long numer, + long denom + ) +{ + ldiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + /* did division wrong; must fix up */ + ++result.quot; + result.rem -= denom; + } + + return result; +} diff --git a/private/crt32/misc/lfind.c b/private/crt32/misc/lfind.c new file mode 100644 index 000000000..7b7443cbd --- /dev/null +++ b/private/crt32/misc/lfind.c @@ -0,0 +1,79 @@ +/*** +*lfind.c - do a linear search +* +* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _lfind() - do a linear search of an array. +* +*Revision History: +* 06-19-85 TC initial version +* 02-05-87 BM changed <= to < in while condition to fix bug +* of looking one element too far +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-21-88 JCR Backed out _LOAD_DS... +* 10-30-89 JCR Added _cdecl to prototypes +* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and +* fixed the copyright. Also, cleaned up the formatting +* a bit. +* 04-05-90 GJF Added #include <search.h> and fixed the resulting +* compilation errors and warnings. Also, removed an +* unreferenced local variable. +* 07-25-90 SBM Replaced <stdio.h> by <stddef.h> +* 10-04-90 GJF New-style function declarator. +* 01-17-91 GJF ANSI naming. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <search.h> +#include <stddef.h> + +/*** +*char *_lfind(key, base, num, width, compare) - do a linear search +* +*Purpose: +* Performs a linear search on the array, looking for the value key +* in an array of num elements of width bytes in size. Returns +* a pointer to the array value if found, NULL if not found. +* +*Entry: +* char *key - key to search for +* char *base - base of array to search +* unsigned *num - number of elements in array +* int width - number of bytes in each array element +* int (*compare)() - pointer to function that compares two +* array values, returning 0 if they are equal and non-0 +* if they are different. Two pointers to array elements +* are passed to this function. +* +*Exit: +* if key found: +* returns pointer to array element +* if key not found: +* returns NULL +* +*Exceptions: +* +*******************************************************************************/ + +void * _CALLTYPE1 _lfind ( + REG2 const void *key, + REG1 const void *base, + REG3 unsigned int *num, + unsigned int width, + int (_CALLTYPE1 *compare)(const void *, const void *) + ) +{ + unsigned int place = 0; + while (place < *num ) + if (!(*compare)(key,base)) + return( (void *)base ); + else + { + base = (char *)base + width; + place++; + } + return( NULL ); +} diff --git a/private/crt32/misc/lsearch.c b/private/crt32/misc/lsearch.c new file mode 100644 index 000000000..42b870764 --- /dev/null +++ b/private/crt32/misc/lsearch.c @@ -0,0 +1,87 @@ +/*** +*lsearch.c - linear search of an array +* +* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* contains the _lsearch() function - linear search of an array +* +*Revision History: +* 06-19-85 TC initial version +* 05-14-87 JMB added function pragma for memcpy in compact/large mode +* for huge pointer support +* include sizeptr.h for SIZED definition +* 08-01-87 SKS Add include file for prototype of memcpy() +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-21-88 JCR Backed out _LOAD_DS... +* 10-30-89 JCR Added _cdecl to prototypes +* 03-14-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and +* fixed the copyright. Also, cleaned up the formatting +* a bit. +* 04-05-90 GJF Added #include <search.h> and fixed the resulting +* compiler errors and warnings. Removed unreferenced +* local variable. Also, removed #include <sizeptr.h>. +* 07-25-90 SBM Replaced <stdio.h> by <stddef.h> +* 10-04-90 GJF New-style function declarator. +* 01-17-91 GJF ANSI naming. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stddef.h> +#include <search.h> +#include <memory.h> + +/*** +*char *_lsearch(key, base, num, width, compare) - do a linear search +* +*Purpose: +* Performs a linear search on the array, looking for the value key +* in an array of num elements of width bytes in size. Returns +* a pointer to the array value if found; otherwise adds the +* key to the end of the list. +* +*Entry: +* char *key - key to search for +* char *base - base of array to search +* unsigned *num - number of elements in array +* int width - number of bytes in each array element +* int (*compare)() - pointer to function that compares two +* array values, returning 0 if they are equal and non-0 +* if they are different. Two pointers to array elements +* are passed to this function. +* +*Exit: +* if key found: +* returns pointer to array element +* if key not found: +* adds the key to the end of the list, and increments +* *num. +* returns pointer to new element. +* +*Exceptions: +* +*******************************************************************************/ + +void * _CALLTYPE1 _lsearch ( + REG2 const void *key, + REG1 void *base, + REG3 unsigned int *num, + unsigned int width, + int (_CALLTYPE1 *compare)(const void *, const void *) + ) +{ + unsigned int place = 0; + while (place < *num ) + if (!(*compare)(key,base)) + return(base); + else + { + base = (char *)base + width; + place++; + } + (void) memcpy( base, key, width ); + (*num)++; + return( base ); +} diff --git a/private/crt32/misc/makefile b/private/crt32/misc/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/crt32/misc/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/crt32/misc/makepath.c b/private/crt32/misc/makepath.c new file mode 100644 index 000000000..6cf245500 --- /dev/null +++ b/private/crt32/misc/makepath.c @@ -0,0 +1,128 @@ +/*** +*makepath.c - create path name from components +* +* Copyright (c) 1987-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* To provide support for creation of full path names from components +* +*Revision History: +* 06-13-87 DFW initial version +* 08-05-87 JCR Changed appended directory delimeter from '/' to '\'. +* 09-24-87 JCR Removed 'const' from declarations (caused cl warnings). +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 11-20-89 GJF Fixed copyright, indents. Added const to types of +* appropriate args. +* 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include +* <cruntime.h>. +* 10-04-90 GJF New-style function declarator. +* 06-09-93 KRS Add _MBCS support. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#ifdef _MBCS +#include <mbdata.h> +#include <mbstring.h> +#endif + +/*** +*void _makepath() - build path name from components +* +*Purpose: +* create a path name from its individual components +* +*Entry: +* char *path - pointer to buffer for constructed path +* char *drive - pointer to drive component, may or may not contain +* trailing ':' +* char *dir - pointer to subdirectory component, may or may not include +* leading and/or trailing '/' or '\' characters +* char *fname - pointer to file base name component +* char *ext - pointer to extension component, may or may not contain +* a leading '.'. +* +*Exit: +* path - pointer to constructed path name +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _makepath ( + register char *path, + const char *drive, + const char *dir, + const char *fname, + const char *ext + ) +{ + register const char *p; + + /* we assume that the arguments are in the following form (although we + * do not diagnose invalid arguments or illegal filenames (such as + * names longer than 8.3 or with illegal characters in them) + * + * drive: + * A ; or + * A: + * dir: + * \top\next\last\ ; or + * /top/next/last/ ; or + * either of the above forms with either/both the leading + * and trailing / or \ removed. Mixed use of '/' and '\' is + * also tolerated + * fname: + * any valid file name + * ext: + * any valid extension (none if empty or null ) + */ + + /* copy drive */ + + if (drive && *drive) { + *path++ = *drive; + *path++ = ':'; + } + + /* copy dir */ + + if ((p = dir) && *p) { + do { + *path++ = *p++; + } + while (*p); +#ifdef _MBCS + if (*(p=_mbsdec(dir,p)) != '/' && *p != '\\') { +#else + if (*(p-1) != '/' && *(p-1) != '\\') { +#endif + *path++ = '\\'; + } + } + + /* copy fname */ + + if (p = fname) { + while (*p) { + *path++ = *p++; + } + } + + /* copy ext, including 0-terminator - check to see if a '.' needs + * to be inserted. + */ + + if (p = ext) { + if (*p && *p != '.') { + *path++ = '.'; + } + while (*path++ = *p++) + ; + } + else { + /* better add the 0-terminator */ + *path = '\0'; + } +} diff --git a/private/crt32/misc/mbval.c b/private/crt32/misc/mbval.c new file mode 100644 index 000000000..aa3ad3a16 --- /dev/null +++ b/private/crt32/misc/mbval.c @@ -0,0 +1,22 @@ +/*** +*mbval.c - definition of __invalid_mb_chars variable +* +* Copyright (c) 1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines __invalid_mb_chars and adds a pointer to __set_invalid_mb_chars +* to be called at runtime startup. +* +** +*Revision History: +* 10-22-93 CFW Module created. +* +*******************************************************************************/ + +void __set_invalid_mb_chars(void); + +int __invalid_mb_chars = 0; + +#pragma data_seg(".CRT$XIC") +void (*__pfn_set_invalid_mb_chars) = __set_invalid_mb_chars; + diff --git a/private/crt32/misc/mips/chandler.c b/private/crt32/misc/mips/chandler.c new file mode 100644 index 000000000..4721f82b1 --- /dev/null +++ b/private/crt32/misc/mips/chandler.c @@ -0,0 +1,219 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + chandler.c + +Abstract: + + This module implements the C specific exception handler that provides + structured condition handling for the C language. + +Author: + + David N. Cutler (davec) 11-Sep-1990 + +Environment: + + Any mode. + +Revision History: + +--*/ + +#include "nt.h" + + +// +// Define procedure prototypes for exception filter and termination handler +// execution routines defined in jmpunwnd.s +// + +LONG +__C_ExecuteExceptionFilter ( + PEXCEPTION_POINTERS ExceptionPointers, + EXCEPTION_FILTER ExceptionFilter, + ULONG EstablisherFrame + ); + +VOID +__C_ExecuteTerminationHandler ( + BOOLEAN AbnormalTermination, + TERMINATION_HANDLER TerminationHandler, + ULONG EstablisherFrame + ); + +EXCEPTION_DISPOSITION +__C_specific_handler ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PDISPATCHER_CONTEXT DispatcherContext + ) + +/*++ + +Routine Description: + + This function scans the scope tables associated with the specified + procedure and calls exception and termination handlers as necessary. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + EstablisherFrame - Supplies a pointer to frame of the establisher function. + + ContextRecord - Supplies a pointer to a context record. + + DispatcherContext - Supplies a pointer to the exception dispatcher or + unwind dispatcher context. + +Return Value: + + If the exception is handled by one of the exception filter routines, then + there is no return from this routine and RtlUnwind is called. Otherwise, + an exception disposition value of continue execution or continue search is + returned. + +--*/ + +{ + + ULONG ControlPc; + EXCEPTION_FILTER ExceptionFilter; + EXCEPTION_POINTERS ExceptionPointers; + PRUNTIME_FUNCTION FunctionEntry; + ULONG Index; + PSCOPE_TABLE ScopeTable; + ULONG TargetPc; + TERMINATION_HANDLER TerminationHandler; + LONG Value; + + // + // Get address of where control left the establisher, the address of the + // function table entry that describes the function, and the address of + // the scope table. + // + + ControlPc = DispatcherContext->ControlPc; + FunctionEntry = DispatcherContext->FunctionEntry; + ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData); + + // + // If an unwind is not in progress, then scan the scope table and call + // the appropriate exception filter routines. Otherwise, scan the scope + // table and call the appropriate termination handlers using the target + // PC obtained from the context record. + // are called. + // + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { + + // + // Scan the scope table and call the appropriate exception filter + // routines. + // + + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) && + (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) { + + // + // Call the exception filter routine. + // + + ExceptionFilter = + (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress; + Value = __C_ExecuteExceptionFilter(&ExceptionPointers, + ExceptionFilter, + (ULONG)EstablisherFrame); + + // + // If the return value is less than zero, then dismiss the + // exception. Otherwise, if the value is greater than zero, + // then unwind to the target exception handler. Otherwise, + // continue the search for an exception filter. + // + + if (Value < 0) { + return ExceptionContinueExecution; + + } else if (Value > 0) { + RtlUnwind(EstablisherFrame, + (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget, + ExceptionRecord, + (PVOID)ExceptionRecord->ExceptionCode); + } + } + } + + } else { + + // + // Scan the scope table and call the appropriate termination handler + // routines. + // + + TargetPc = ContextRecord->Fir; + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) { + + // + // If the target PC is within the same scope the control PC + // is within, then this is an uplevel goto out of an inner try + // scope or a long jump back into a try scope. Terminate the + // scan termination handlers. + // + // N.B. The target PC can be just beyond the end of the scope, + // in which case it is a leave from the scope. + // + + + if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) { + break; + + } else { + + // + // If the scope table entry describes an exception filter + // and the associated exception handler is the target of + // the unwind, then terminate the scan for termination + // handlers. Otherwise, if the scope table entry describes + // a termination handler, then record the address of the + // end of the scope as the new control PC address and call + // the termination handler. + // + + if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) { + if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) { + break; + } + + } else { + DispatcherContext->ControlPc = + ScopeTable->ScopeRecord[Index].EndAddress + 4; + TerminationHandler = + (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress; + __C_ExecuteTerminationHandler(TRUE, + TerminationHandler, + (ULONG)EstablisherFrame); + } + } + } + } + } + + // + // Continue search for exception or termination handlers. + // + + return ExceptionContinueSearch; +} diff --git a/private/crt32/misc/mips/jmpuwind.s b/private/crt32/misc/mips/jmpuwind.s new file mode 100644 index 000000000..8e99fcc4c --- /dev/null +++ b/private/crt32/misc/mips/jmpuwind.s @@ -0,0 +1,138 @@ +// TITLE("Jump to Unwind") +//++ +// +// Copyright (c) 1992 Microsoft Corporation +// +// Module Name: +// +// jmpuwind.s +// +// Abstract: +// +// This module implements the MIPS specific routine to jump to the runtime +// time library unwind routine. +// +// Author: +// +// David N. Cutler (davec) 12-Sep-1990 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksmips.h" + SBTTL("Execute Exception Filter") +//++ +// +// ULONG +// __C_ExecuteExceptionFilter ( +// PEXCEPTION_POINTERS ExceptionPointers, +// EXCEPTION_FILTER ExceptionFilter, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function sets the static link and transfers control to the specified +// exception filter routine. +// +// Arguments: +// +// ExceptionPointers (a0) - Supplies a pointer to the exception pointers +// structure. +// +// ExceptionFilter (a1) - Supplies the address of the exception filter +// routine. +// +// EstablisherFrame (a2) - Supplies the establisher frame pointer. +// +// Return Value: +// +// The value returned by the exception filter routine. +// +//-- + + LEAF_ENTRY(__C_ExecuteExceptionFilter) + + move v0,a2 // set static link + j a1 // transfer control to exception filter + + .end __C_ExecuteExceptionFilter + + SBTTL("Execute Termination Handler") +//++ +// +// VOID +// __C_ExecuteTerminationHandler ( +// BOOLEAN AbnormalTermination, +// TERMINATION_HANDLER TerminationHandler, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function sets the static link and transfers control to the specified +// termination handler routine. +// +// Arguments: +// +// AbnormalTermination (a0) - Supplies a boolean value that determines +// whether the termination is abnormal. +// +// TerminationHandler (a1) - Supplies the address of the termination handler +// routine. +// +// EstablisherFrame (a2) - Supplies the establisher frame pointer. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(__C_ExecuteTerminationHandler) + + move v0,a2 // set static link + j a1 // transfer control to termination handler + + .end __C_ExecuteTerminationHandler + + SBTTL("Jump to Unwind") +//++ +// +// VOID +// __jump_unwind ( +// IN PVOID EstablishFrame, +// IN PVOID TargetPc +// ) +// +// Routine Description: +// +// This function transfer control to unwind. It is used by the MIPS +// compiler when a goto out of the body or a try statement occurs. +// +// Arguments: +// +// EstablishFrame (a0) - Supplies the establisher frame point of the +// target of the unwind. +// +// TargetPc (a1) - Supplies the target instruction address where control +// is to be transfered to after the unwind operation is complete. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(__jump_unwind) + + move a2,zero // set NULL exception record address + move a3,zero // set destination return value + j RtlUnwind // unwind to specified target + + .end __jump_unwind diff --git a/private/crt32/misc/mips/longjmp.s b/private/crt32/misc/mips/longjmp.s new file mode 100644 index 000000000..04e886570 --- /dev/null +++ b/private/crt32/misc/mips/longjmp.s @@ -0,0 +1,128 @@ +// TITLE("Long Jump") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// +// Module Name: +// +// longjmp.s +// +// Abstract: +// +// This module implements the MIPS specific routine to perform a long +// jump operation. +// +// N.B. This routine conditionally provides UNSAFE handling of longjmp +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an unitialized variable +// has been set to a nonzero value. +// +// Author: +// +// David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksmips.h" + + SBTTL("Long Jump") +//++ +// +// int +// longjmp ( +// IN jmp_buf JumpBuffer, +// IN int ReturnValue +// ) +// +// Routine Description: +// +// This function performs a long jump to the context specified by the +// jump buffer. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer that contains +// jump information. +// +// ReturnValue (a1) - Supplies the value that is to be returned to the +// caller of set jump. +// +// Return Value: +// +// None. +// +//-- + + .struct 0 + .space 4 * 4 // argument save area +LjEr: .space ExceptionRecordLength // exception record + .space 4 * 3 // fill +LjRa: .space 4 // saved return address +LongjmpFrameLength: + + NESTED_ENTRY(longjmp, LongjmpFrameLength, zero) + + subu sp,sp,LongjmpFrameLength // allocate stack frame + sw ra,LjRa(sp) // save return address + + PROLOGUE_END + + bne zero,a1,10f // if ne, return value specified + li a1,1 // set return value to nonzero value +10: lw v0,JbType(a0) // get safe setjmp/longjmp flag + bne zero,v0,20f // if ne, provide safe longjmp + +// +// Provide unsafe handling of longjmp. +// + + move v0,a1 // set return value + ldc1 f20,JbFltF20(a0) // restore floating registers f20 - f31 + ldc1 f22,JbFltF22(a0) // + ldc1 f24,JbFltF24(a0) // + ldc1 f26,JbFltF26(a0) // + ldc1 f28,JbFltF28(a0) // + ldc1 f30,JbFltF30(a0) // + lw s0,JbIntS0(a0) // restore integer registers s0 - s8 + lw s1,JbIntS1(a0) // + lw s2,JbIntS2(a0) // + lw s3,JbIntS3(a0) // + lw s4,JbIntS4(a0) // + lw s5,JbIntS5(a0) // + lw s6,JbIntS6(a0) // + lw s7,JbIntS7(a0) // + lw s8,JbIntS8(a0) // + lw a1,JbFir(a0) // get setjmp return address + lw sp,JbIntSp(a0) // restore stack pointer + j a1 // jump back to setjmp site + +// +// Provide safe handling of longjmp. +// +// An exception record is constructed that contains a log jump status +// code and the first exception information parameter is a pointer to +// the jump buffer. +// + +20: li v0,STATUS_LONGJUMP // get long jump status code + sw v0,LjEr + ErExceptionCode(sp) // set exception code + sw zero,LjEr + ErExceptionFlags(sp) // clear exception flags + sw zero,LjEr + ErExceptionRecord(sp) // clear associate record + sw zero,LjEr + ErExceptionAddress(sp) // clear exception address + li v0,1 // set number of parameters + sw v0,LjEr + ErNumberParameters(sp) // + sw a0,LjEr + ErExceptionInformation(sp) // set jump buffer address + move a3,a1 // set return value + addu a2,sp,LjEr // compute exception record address + lw a1,JbFir(a0) // set target instruction address + lw a0,JbType(a0) // set target virtual frame address + jal RtlUnwind // finish in common code + b 20b + + .end longjmp diff --git a/private/crt32/misc/mips/setjmp.s b/private/crt32/misc/mips/setjmp.s new file mode 100644 index 000000000..245cd4b37 --- /dev/null +++ b/private/crt32/misc/mips/setjmp.s @@ -0,0 +1,101 @@ +// TITLE("Set Jump") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// +// Module Name: +// +// setjmp.s +// +// Abstract: +// +// This module implements the MIPS specific routine to perform a setjmp. +// +// N.B. This module conditionally provides UNSAFE handling of setjmp and +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an uninitialized variable +// has been set to a nonzero value. +// +// Author: +// +// David N. Cutler (davec) 7-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksmips.h" + +// +// Define variable that will cause setjmp/longjmp to be safe or unsafe with +// respect to structured exception handling. +// + + .globl _setjmpexused + .comm _setjmpexused , 4 + + SBTTL("Set Jump") +//++ +// +// int +// setjmp ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function saved the current nonvolatile register state in the +// specified jump buffer and returns a function vlaue of zero. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + LEAF_ENTRY(setjmp) + + lw v0,_setjmpexused // get value of switch variable + bne zero,v0,10f // if ne, provide safe setjmp + +// +// Provide unsafe handling of setjmp. +// + + sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31 + sdc1 f22,JbFltF22(a0) // + sdc1 f24,JbFltF24(a0) // + sdc1 f26,JbFltF26(a0) // + sdc1 f28,JbFltF28(a0) // + sdc1 f30,JbFltF30(a0) // + sw s0,JbIntS0(a0) // save integer registers s0 - s8 + sw s1,JbIntS1(a0) // + sw s2,JbIntS2(a0) // + sw s3,JbIntS3(a0) // + sw s4,JbIntS4(a0) // + sw s5,JbIntS5(a0) // + sw s6,JbIntS6(a0) // + sw s7,JbIntS7(a0) // + sw s8,JbIntS8(a0) // + sw ra,JbFir(a0) // get setjmp return address + sw sp,JbIntSp(a0) // save stack pointer + sw zero,JbType(a0) // clean safe setjmp flag + move v0,zero // set return value + j ra // return + +// +// Provide safe handling of setjmp. +// + +10: j v0 // finish in common code + + .end setjmp diff --git a/private/crt32/misc/mips/setjmpex.s b/private/crt32/misc/mips/setjmpex.s new file mode 100644 index 000000000..31385e394 --- /dev/null +++ b/private/crt32/misc/mips/setjmpex.s @@ -0,0 +1,156 @@ +// TITLE("Set Jump Extended") +//++ +// +// Copyright (c) 1993 Microsoft Corporation +// +// Module Name: +// +// setjmpex.s +// +// Abstract: +// +// This module implements the MIPS specific routine to provide SAFE +// handling of setjmp/longjmp with respect to structured exception +// handling. +// +// Author: +// +// David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "ksmips.h" + +// +// Define variable that will cause setjmp/longjmp to be safe with respect +// to structured exception handling. +// + + .globl _setjmpexused + .data +_setjmpexused: + .word _setjmpex // set address of safe setjmp routine + + SBTTL("Set Jump Extended") +//++ +// +// int +// _setjmpex ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function transfers control to the actual setjmp routine. +// +// Arguments: +// +// JumpBuffer (a0) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + .struct 0 + .space 4 * 4 // argument save area +SjS0: .space 4 // saved integer register s0 +SjFl: .space 4 // in function flag variable + .space 4 // fill +SjRa: .space 4 // saved return address +SetjmpFrameLength: + + NESTED_ENTRY(_setjmpex, SetjmpFrameLength, zero) + + subu sp,sp,SetjmpFrameLength // allocate stack frame + sw s0,SjS0(sp) // save integer register s0 + sw ra,SjRa(sp) // save return address + move s0,sp // set frame pointer + + PROLOGUE_END + + subu sp,sp,ContextFrameLength + 16 // allocate a context frame + +// +// Save the nonvolatile machine state in both the jump buffer and a context +// record that will be used to compute the virtual frame pointer. +// + + sdc1 f20,JbFltF20(a0) // save floating registers f20 - f31 + sdc1 f22,JbFltF22(a0) // + sdc1 f24,JbFltF24(a0) // + sdc1 f26,JbFltF26(a0) // + sdc1 f28,JbFltF28(a0) // + sdc1 f30,JbFltF30(a0) // + lw v0,SjS0(s0) // get saved integer register s0 + sw v0,JbIntS0(a0) // save integer registers s0 - s8 + sw s1,JbIntS1(a0) // + sw s2,JbIntS2(a0) // + sw s3,JbIntS3(a0) // + sw s4,JbIntS4(a0) // + sw s5,JbIntS5(a0) // + sw s6,JbIntS6(a0) // + sw s7,JbIntS7(a0) // + sw s8,JbIntS8(a0) // + sw ra,JbFir(a0) // get setjmp return address + addu v0,s0,SetjmpFrameLength // compute stack pointer address + sw v0,JbIntSp(a0) // save stack pointer + + sdc1 f20,CxFltF20 + 16(sp) // save floating registers f20 - f31 + sdc1 f22,CxFltF22 + 16(sp) // + sdc1 f24,CxFltF24 + 16(sp) // + sdc1 f26,CxFltF26 + 16(sp) // + sdc1 f28,CxFltF28 + 16(sp) // + sdc1 f30,CxFltF30 + 16(sp) // + lw v0,SjS0(s0) // get saved integer register s0 + sw v0,CxIntS0 + 16(sp) // save integer registers s0 - s8 + sw s1,CxIntS1 + 16(sp) // + sw s2,CxIntS2 + 16(sp) // + sw s3,CxIntS3 + 16(sp) // + sw s4,CxIntS4 + 16(sp) // + sw s5,CxIntS5 + 16(sp) // + sw s6,CxIntS6 + 16(sp) // + sw s7,CxIntS7 + 16(sp) // + sw s8,CxIntS8 + 16(sp) // save integer register s8 + sw gp,CxIntGp + 16(sp) // save integer register gp + addu v0,s0,SetjmpFrameLength // compute stack pointer address + sw v0,CxIntSp + 16(sp) // save stack pointer + sw ra,CxIntRa + 16(sp) // save return address + sw ra,CxFir + 16(sp) // save return address + +// +// Perform unwind to determine the virtual frame pointer of the caller. +// + + addu a0,a0,JbType // set virtual frame address argument + sw a0,4 * 4(sp) // + subu a0,ra,4 // compute control PC address + jal RtlLookupFunctionEntry // lookup function table address + lw a0,SjRa(s0) // get return address + subu a0,a0,4 // compute control PC address + move a1,v0 // set address of function entry + addu a2,sp,16 // compute address of context record + addu a3,s0,SjFl // set address of in function variable + sw zero,4 * 5(sp) // set context pointer array address + jal RtlVirtualUnwind // compute virtual frame pointer value + +// +// Set return value, restore registers, deallocate stack frame, and return. +// + + move v0,zero // set return value + move sp,s0 // reset stack pointer + lw s0,SjS0(sp) // restore integer register s0 + lw ra,SjRa(sp) // restore return address + addu sp,sp,SetjmpFrameLength // deallocate stack frame + j ra // return + + .end _setjmpex diff --git a/private/crt32/misc/mtest.c b/private/crt32/misc/mtest.c new file mode 100644 index 000000000..0e95bcee1 --- /dev/null +++ b/private/crt32/misc/mtest.c @@ -0,0 +1,530 @@ +/*** +* mtest.c - Multi-thread debug testing module +* +* Copyright (c) 19xx-1988, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This source contains a group of routines used for multi-thread +* testing. In order to use the debug flavor of these routines, you +* MUST link special debug versions of multi-thread crt0dat.obj and +* mlock.obj into your program. +* +* [NOTE: This source module is NOT included in the C runtime library; +* it is used only for testing and must be explicitly linked into the +* test program.] +* +*Revision History: +* 12-??-87 JCR Module created. +* 06-17-88 JCR Misc. bug fixes. +* 08-03-88 JCR Use the stdio.h value of _NFILE +* 10-03-88 JCR 386: Use SYS calls, not DOS calls +* 10-04-88 JCR 386: Removed 'far' keyword +* 10-10-88 GJF Made API names match DOSCALLS.H +* 06-08-89 JCR New 386 _beginthread interface; also brought +* lots of new options across from the C600 tree. +* 07-11-89 JCR Added _POPEN_LOCK to _locknames[] array +* 07-14-89 JCR Added _LOCKTAB_LOCK support +* 07-24-90 SBM Removed '32' from API names +* +*******************************************************************************/ + +#ifdef M_I386 +#ifdef STACKALLOC +#error Can't define STACKALLOC in 386 mode +#endif +#endif + +#ifdef M_I386 +#ifdef _DOSCREATETHREAD_ +#error Currently can't define _DOSCREATETHREAD_ in 386 mode +#endif +#endif + +#ifdef _DOSCREATETHREAD_ +#ifndef STACKALLOC +#error Can't define _DOSCREATETHREAD_ without STACKALLOC +#endif +#endif + +/* +Multi-thread core tester module. +*/ +#include <malloc.h> +#include <process.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <io.h> +#include <mtest.h> +#ifdef DEBUG +#include <os2dll.h> +#include <file2.h> +#endif + +/* Define FAR to be blank for the 386 and far otherwise. */ + +#undef FAR +#ifdef M_I386 +#define FAR +#else +#define FAR far +#endif + +/* define stack size */ +#ifdef M_I386 +#define _STACKSIZE_ 8192 +#else +#define _STACKSIZE_ 2048 +#endif + + +/* routines */ +#ifdef M_I386 +unsigned _syscall DOSSLEEP (unsigned long) ; +#else +unsigned FAR pascal DOSSLEEP (unsigned long) ; +#endif +int main ( int argc , char * * argv ) ; +int minit(void); +void childcode ( void FAR * arg ) ; +#ifdef _DOSCREATETHREAD_ +#ifndef M_I386 +void childcode ( void ) ; +unsigned FAR pascal DOSCREATETHREAD (void FAR *, void FAR *, void FAR *); +#endif +#else +void childcode ( void FAR * arg ) ; +#endif +int mterm(void); + +/* global data */ +char Result [ _THREADMAX_ ] ; +unsigned Synchronize ; + +#ifdef DEBUG +/* Array of lock names. This order must match the declarations in + os2dll.h and os2dll.inc. */ + +char *_locknames[] = { + "** NO LOCK 0 ** ", /* lock values are 1-based */ + "_SIGNAL_LOCK ", + "_IOB_SCAN_LOCK ", + "_TMPNAM_LOCK ", + "_INPUT_LOCK ", + "_OUTPUT_LOCK ", + "_CSCANF_LOCK ", + "_CPRINTF_LOCK ", + "_CONIO_LOCK ", + "_HEAP_LOCK ", + "_BHEAP_LOCK ", + "_TIME_LOCK ", + "_ENV_LOCK ", + "_EXIT_LOCK1 ", + "_EXIT_LOCK2 ", + "_THREADDATA_LOCK", + "_POPEN_LOCK ", + "_SSCANF_LOCK ", + "_SPRINTF_LOCK ", +#ifdef M_I386 + "_VSPRINTF_LOCK ", + "_LOCKTAB_LOCK " +#else + "_VSPRINTF_LOCK " +#endif + }; + +/* Minimal sanity check on above array. */ +#ifdef M_I386 + +#if ((_LOCKTAB_LOCK+1)-_STREAM_LOCKS) +#error *** _locknames[] does agree with lock values *** +#endif + +#else /* !M_I386 */ + +#if ((_VSPRINTF_LOCK+1)-_STREAM_LOCKS) +#error *** _locknames[] does agree with lock values *** +#endif + +#endif /* M_I386 */ + +#endif /* DEBUG */ + + +/*** +* main() - Main mthread testing shell +* +*Purpose: +* Provides a general purpose shell for mthread testing. +* The module does the following: +* +* (1) Call minit() to perform test initialization operations. +* +* (2) Begins one thread for each argument passed to the +* program. Each thread is passed the corresponding argument. +* Thread begin location is assumed to be at routine childcode(); +* +* (3) Waits for all threads to terminate. +* +* (4) Calls mterm() to perform termination operations. +* +* Note that minit(), childcode(), and mterm() are routines that +* are external to this source. Again, this source doesn't care +* what their purpose or operation is. +* +* Also, childcode() is expected to conform to the following rules: +* +* (1) The childcode should not start running until +* the variable 'Synchronize' becomes non-zero. +* +* (2) When the thread is done executing, it should set +* the value Result[threadid] to a non-zero value so the +* parent (i.e., this routine) knows it has completed. +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +int main ( int argc , char * * argv ) +{ + int rc ; + unsigned result = 0 ; + long ChildCount ; + int NumThreads ; + int t ; + int r ; + int MaxThread = 0 ; + long LoopCount ; +#ifdef THREADLOOP + char **argvsave; +#endif +#ifndef M_I386 + char * stackbottom ; +#endif + +#ifdef DEBUG + if ( argc > MAXTHREADID) { + printf("*** ERROR: Mthread debugging only supports %u threads ***\n", MAXTHREADID); + return(-1); + } +#endif + + if ( -- argc > (_THREADMAX_-1) ) + { + printf ( "*** Error: Too many arguments***\n" ) ; + return (-1) ; + } + + /* Call the initiation routine */ + + if (minit() != 0) { + printf("*** Error: From minit() routine ***\n"); + return(-1); + } + + /* Bring up the threads */ + + printf ( "Process ID = %u, Thread ID = %d, ArgCount= %d\r\n" , + getpid ( ) , * _threadid , argc ) ; + +#ifndef M_I386 +#ifdef STACKALLOC + printf( "(thread stacks allocated explicilty by mtest suite)\r\n"); +#else + printf( "(thread stacks allocated implicitly via _beginthread)\r\n"); +#endif +#endif + +#ifdef THREADLOOP + /* Bring up all the threads several times (so tids get re-used) */ + argvsave=argv; + for (threadloop=1;threadloop<=_THREADLOOPCNT_;threadloop++) { + printf("\nThreadloop = %i\n", threadloop); + argv=argvsave; +#endif + + NumThreads = 0 ; + + while ( * ++ argv ) + { + + ChildCount = atol ( * argv ) ; + +#ifdef M_I386 + + rc = _beginthread ( (void FAR *) childcode , _STACKSIZE_ , + (void FAR *) ChildCount ) ; + + if ( rc == -1 ) + +#else /* !M_I386 */ + +#ifdef STACKALLOC + if ( ! ( stackbottom = _fmalloc ( _STACKSIZE_ ) ) ) + { + printf ( "*** Error: Could not allocate a stack ***\n" ) ; + break ; + } +#else + stackbottom = (void FAR *) NULL; +#endif + +#ifdef _DOSCREATETHREAD_ + stackbottom+=_STACKSIZE_-16; /* point to end of malloc'd block */ + rc1 = DOSCREATETHREAD( (void FAR *) childcode, &rc, + (void FAR *) stackbottom); + + if (rc1 != 0) +#else + rc = _beginthread ( (void FAR *) childcode , (void FAR *) stackbottom , + _STACKSIZE_ , (void FAR *) ChildCount ) ; + + if ( rc == -1 ) +#endif + +#endif /* M_I386 */ + + { + printf ("*** Error: Could not Spawn %d-th Thread (argument=%ld) ***\n" , + NumThreads + 1 , ChildCount ) ; + break ; + } + + if ( rc > MaxThread ) + MaxThread = rc ; + + printf ( "Spawning %d-th Thread %d with argument=%ld\r\n" , + ++ NumThreads , rc , ChildCount ) ; + } + + printf ( "NumThreads = %d, MaxThread = %d\r\n" , + NumThreads, MaxThread ) ; + + /* Let the threads begin and wait for them to term. */ + + LoopCount = 0L ; + + Synchronize = 1 ; + + for ( t = 0 ; t < NumThreads ; ++ t ) + { + r = 0 ; + while ( ! Result [ r ] ) + { + DOSSLEEP ( 0L ) ; + if ( ++ r > MaxThread ) + { + r = 0 ; + printf ( "%ld\r" , LoopCount ++ ) ; + } + } + + printf ( "%d: Thread %d Done.\r\n" , t , r) ; + + Result [ r ] = '\0' ; + } +#ifdef THREADLOOP + } +#endif + + /* All the threads have completed. Call the term routine and return. */ + + if (mterm() != 0) { + printf("*** Error: From mterm() routine ***\n"); + return(-1); + } + + printf("\nDone!\n"); + return 0 ; +} + + +#ifdef DEBUG + +/*** +* Debug Print Routines - Display useful mthread lock data +* +*Purpose: +* The following routines extract information from the multi-thread +* debug data bases and print them out in various formats. +* In order to use these routines, you MUST link special debug +* versions of multi-thread crt0dat.obj and mlock.obj into your program. +* +*Entry: +* +*Exit: +* 0 = success +* 0! = failure +* +*Exceptions: +* +*******************************************************************************/ + +/*--- Print lock routine ---*/ +int printlock(int locknum) +{ + int retval; + +#ifdef _INIT_LOCKS + if (locknum >= _STREAM_LOCKS) + printf("\nValidating lock #%i (%s):\n",locknum, "not a 'single lock'"); + else + printf("\nValidating lock #%i: %s\n",locknum, _locknames[locknum]); +#else + printf("\nValidating lock #%i (%s, %s):\n", + locknum, + (locknum >= _STREAM_LOCKS ? + "not a 'single' lock" : _locknames[locknum]), + (_lock_exist(locknum) ? + "initialized" : "NOT initialized") + ); +#endif + + retval = _check_lock(locknum); + printf("\tLock count = %u\r\n", _lock_cnt(locknum)); + printf("\tCollision count = %u\r\n", _collide_cnt(locknum)); + + if (retval != 0) + printf("\t*** ERROR: Checking lock ***\n"); + + return(retval); +} + + +/*--- Printf single locks ---*/ +int print_single_locks(void) +{ + int locknum; + int retval=0; + int lockval; + + printf("\n--- Single Locks ---\n"); + +#ifdef _INIT_LOCKS + printf("\t\t\t\tlock count\tcollide count\n"); + for (locknum=1;locknum<_STREAM_LOCKS;locknum++) { + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("#%i / %s\t\t%u\t\t%u\t%s\n", + locknum, _locknames[locknum], _lock_cnt(locknum), + _collide_cnt(locknum), (lockval ? "*LOCK ERROR*" : "") ); + } +#else + printf("\t\t\t\tlock count\tcollide count\texists?\n"); + for (locknum=1;locknum<_STREAM_LOCKS;locknum++) { + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("#%i / %s\t\t%u\t\t%u\t\t%s\t%s\n", + locknum, _locknames[locknum], _lock_cnt(locknum), + _collide_cnt(locknum), + (_lock_exist(locknum) ? "YES" : "NO"), + (lockval ? "*LOCK ERROR*" : "") ); + } +#endif + + return(retval); +} + + +/*--- Print all stdio locks ---*/ +int print_stdio_locks(void) +{ + int i; + int locknum; + int retval=0; + int lockval; + + printf("\n--- Stdio Locks ---\n"); + +#ifdef _INIT_LOCKS + printf("stream\t\tlock count\tcollide count\n"); + for (i=0;i<_NFILE;i++) { + locknum = _stream_locknum(i); + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("%i\t\t%u\t\t%u\t%s\n", + i, _lock_cnt(locknum), _collide_cnt(locknum), + (lockval ? "*LOCK ERROR*" : "") ); + } +#else + printf("stream\t\tlock count\tcollide count\texists?\n"); + for (i=0;i<_NFILE;i++) { + locknum = _stream_locknum(i); + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("%i\t\t%u\t\t%u\t\t%s\t%s\n", + i, _lock_cnt(locknum), _collide_cnt(locknum), + (_lock_exist(locknum) ? "YES" : "NO"), + (lockval ? "*LOCK ERROR*" : "") ); + } +#endif + + return(retval); +} + + +/*--- Print all lowio locks ---*/ +int print_lowio_locks(void) +{ + int i; + int locknum; + int retval=0; + int lockval; + + printf("\n--- Lowio locks ---\n"); + +#ifdef _INIT_LOCKS + printf("fh\t\tlock count\tcollide count\n"); + for (i=0;i<_NFILE;i++) { + locknum = _fh_locknum(i); + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("%i\t\t%u\t\t%u\t%s\n", + i, _lock_cnt(locknum), _collide_cnt(locknum), + (lockval ? "*LOCK ERROR*" : "") ); + } +#else + printf("fh\t\tlock count\tcollide count\texists?\n"); + for (i=0;i<_NFILE;i++) { + locknum = _fh_locknum(i); + if (lockval = (_check_lock(locknum) != 0)) + retval++; + printf("%i\t\t%u\t\t%u\t\t%s\t%s\n", + i, _lock_cnt(locknum), _collide_cnt(locknum), + (_lock_exist(locknum) ? "YES" : "NO"), + (lockval ? "*LOCK ERROR*" : "") ); + } +#endif + + return(retval); +} + + +/*--- Print all I/O locks ---*/ +int print_iolocks(void) +{ + int retval=0; + + retval += print_stdio_locks(); + retval += print_lowio_locks(); + + return(retval); +} + + +/*--- Print all Locks ---*/ +int print_locks(void) +{ + int retval=0; + + retval += print_single_locks(); + retval += print_iolocks(); + + return(retval); +} + +#endif diff --git a/private/crt32/misc/nlsdata1.c b/private/crt32/misc/nlsdata1.c new file mode 100644 index 000000000..6b5a9b2b7 --- /dev/null +++ b/private/crt32/misc/nlsdata1.c @@ -0,0 +1,38 @@ +/*** +*nlsdata1.c - globals for international library - small globals +* +* Copyright (c) 1991-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This module contains the globals: __mb_cur_max, _decimal_point, +* _decimal_point_length. This module is always required. +* This module is separated from nlsdatax.c for granularity. +* +*Revision History: +* 12-01-91 ETC Created. +* 04-03-92 PLM Changes tdef.h to tchar.h +* 08-18-92 KRS Rip out _tflag--not used. +* +*******************************************************************************/ + +#include <stdlib.h> +#include <nlsint.h> + +/* + * Value of MB_CUR_MAX macro. + */ +unsigned short __mb_cur_max = 1; + +/* + * Localized decimal point string. + */ +char _decimal_point[] = "."; + +#ifdef _INTL + +/* + * Decimal point length, not including terminating null. + */ +size_t _decimal_point_length = 1; + +#endif /* _INTL */ diff --git a/private/crt32/misc/nlsdata2.c b/private/crt32/misc/nlsdata2.c new file mode 100644 index 000000000..7cbca2a2f --- /dev/null +++ b/private/crt32/misc/nlsdata2.c @@ -0,0 +1,34 @@ +/*** +*nlsdata2.c - globals for international library - locale handles and code page +* +* Copyright (c) 1991-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This module defines the locale handles and code page. The handles are +* required by almost all locale dependent functions. This module is +* separated from nlsdatax.c for granularity. +* +*Revision History: +* 12-01-91 ETC Created. +* +*******************************************************************************/ + +#include <locale.h> +#include <setlocal.h> + +/* + * Locale handles. + */ +LCID _lc_handle[LC_MAX-LC_MIN+1] = { + _CLOCALEHANDLE, + _CLOCALEHANDLE, + _CLOCALEHANDLE, + _CLOCALEHANDLE, + _CLOCALEHANDLE, + _CLOCALEHANDLE +}; + +/* + * Code page. + */ +UINT _lc_codepage = _CLOCALECP; /* CP_ACP */ diff --git a/private/crt32/misc/nlsdata3.c b/private/crt32/misc/nlsdata3.c new file mode 100644 index 000000000..5e57d2111 --- /dev/null +++ b/private/crt32/misc/nlsdata3.c @@ -0,0 +1,34 @@ +/*** +*nlsdata3.c - globals for international library - locale id's +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This module contains the definition of locale id's. These id's and +* this file should only be visible to the _init_(locale category) +* functions. This module is separated from nlsdatax.c for granularity. +* +*Revision History: +* 12-01-91 ETC Created. +* 01-25-93 KRS Updated. +* +*******************************************************************************/ + +#ifdef _INTL +#include <locale.h> +#include <setlocal.h> + +/* + * Locale id's. + */ +/* UNDONE: define struct consisting of LCID/LANGID, CTRY ID, and CP. */ +LC_ID _lc_id[LC_MAX-LC_MIN+1] = { + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 } +}; + +#endif /* _INTL */ diff --git a/private/crt32/misc/onexit.c b/private/crt32/misc/onexit.c new file mode 100644 index 000000000..13806f41a --- /dev/null +++ b/private/crt32/misc/onexit.c @@ -0,0 +1,286 @@ +/*** +*onexit.c - save function for execution on exit +* +* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _onexit(), atexit() - save function for execution at exit +* +* In order to save space, the table is allocated via malloc/realloc, +* and only consumes as much space as needed. __onexittable is +* set to point to the table if onexit() is ever called. +* +*Revision History: +* 06-30-89 PHG module created, based on asm version +* 03-15-90 GJF Replace _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, +* cleaned up the formatting a bit. +* 05-21-90 GJF Fixed compiler warning. +* 10-04-90 GJF New-style function declarators. +* 12-28-90 SRW Added casts of func for Mips C Compiler +* 01-21-91 GJF ANSI naming. +* 09-09-91 GJF Revised for C++ needs. +* 03-20-92 SKS Revamped for new initialization model +* 04-23-92 DJM POSIX support. +* 12-02-93 SKS Add __dllonexit for DLLs using CRTDLL.DLL +* +*******************************************************************************/ + +#include <cruntime.h> +#include <os2dll.h> +#include <stdlib.h> +#include <internal.h> + +void __cdecl _onexitinit(void); + +#ifdef _MSC_VER + +#pragma data_seg(".CRT$XIC") +static void (__cdecl *pinit)(void) = _onexitinit; +#pragma data_seg() + +#endif /* _MSC_VER */ + +#include <malloc.h> +#include <rterr.h> + +typedef void (_CALLTYPE1 *PF)(void); /* pointer to function */ + +/* + * Define pointers to beginning and end of the table of function pointers + * manipulated by _onexit()/atexit(). + */ +extern PF *__onexitbegin; +extern PF *__onexitend; + +/* + * Define increment (in entries) for growing the _onexit/atexit table + */ +#define ONEXITTBLINCR 4 + +/*** +*_onexit(func), atexit(func) - add function to be executed upon exit +* +*Purpose: +* The _onexit/atexit functions are passed a pointer to a function +* to be called when the program terminate normally. Successive +* calls create a register of functions that are executed last in, +* first out. +* +*Entry: +* void (*func)() - pointer to function to be executed upon exit +* +*Exit: +* onexit: +* Success - return pointer to user's function. +* Error - return NULL pointer. +* atexit: +* Success - return 0. +* Error - return non-zero value. +* +*Notes: +* This routine depends on the behavior of _initterm() in CRT0DAT.C. +* Specifically, _initterm() must not skip the address pointed to by +* its first parameter, and must also stop before the address pointed +* to by its second parameter. This is because _onexitbegin will point +* to a valid address, and _onexitend will point at an invalid address. +* +*Exceptions: +* +*******************************************************************************/ + + +_onexit_t _CALLTYPE1 _onexit ( + _onexit_t func + ) +{ + PF *p; + +#ifdef MTHREAD + _lockexit(); /* lock the exit code */ +#endif + + /* + * First, make sure the table has room for a new entry + */ + if ( _msize(__onexitbegin) <= (unsigned)((char *)__onexitend - + (char *)__onexitbegin) ) { + /* + * not enough room, try to grow the table + */ + if ( (p = (PF *) realloc(__onexitbegin, _msize(__onexitbegin) + + ONEXITTBLINCR * sizeof(PF))) == NULL ) { + /* + * didn't work. don't do anything rash, just fail + */ +#ifdef MTHREAD + _unlockexit(); +#endif + + return NULL; + } + + /* + * update __onexitend and __onexitbegin + */ + __onexitend = p + (__onexitend - __onexitbegin); + __onexitbegin = p; + } + + /* + * Put the new entry into the table and update the end-of-table + * pointer. + */ + *(__onexitend++) = (PF)func; + +#ifdef MTHREAD + _unlockexit(); +#endif + + return func; + +} + +int _CALLTYPE1 atexit ( + PF func + ) +{ + return (_onexit((_onexit_t)func) == NULL) ? -1 : 0; +} + +/*** +* void _onexitinit(void) - initialization routine for the function table +* used by _onexit() and _atexit(). +* +*Purpose: +* Allocate the table with room for 32 entries (minimum required by +* ANSI). Also, initialize the pointers to the beginning and end of +* the table. +* +*Entry: +* None. +* +*Exit: +* No return value. A fatal runtime error is generated if the table +* cannot be allocated. +* +*Notes: +* This routine depends on the behavior of doexit() in CRT0DAT.C. +* Specifically, doexit() must not skip the address pointed to by +* __onexitbegin, and it must also stop before the address pointed +* to by __onexitend. This is because _onexitbegin will point +* to a valid address, and _onexitend will point at an invalid address. +* +* Since the table of onexit routines is built in forward order, it +* must be traversed by doexit() in CRT0DAT.C in reverse order. This +* is because these routines must be called in last-in, first-out order. +* +* If __onexitbegin == __onexitend, then the onexit table is empty! +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _onexitinit ( + void + ) +{ + if ( (__onexitbegin = (PF *)malloc(32 * sizeof(PF))) == NULL ) + /* + * cannot allocate minimal required size. generate + * fatal runtime error. + */ + _amsg_exit(_RT_ONEXIT); + + *(__onexitbegin) = (PF) NULL; + __onexitend = __onexitbegin; +} + +#ifdef CRTDLL + +/*** +*__dllonexit(func, pbegin, pend) - add function to be executed upon DLL detach +* +*Purpose: +* The _onexit/atexit functions in a DLL linked with CRTDLL.LIB +* must maintain their own atexit/_onexit list. This routine is +* the worker that gets called by such DLLs. It is analogous to +* the regular _onexit above except that the __onexitbegin and +* __onexitend variables are not global variables visible to this +* routine but rather must be passed as parameters. +* +*Entry: +* void (*func)() - pointer to function to be executed upon exit +* void (***pbegin)() - pointer to variable pointing to the beginning +* of list of functions to execute on detach +* void (***pend)() - pointer to variable pointing to the end of list +* of functions to execute on detach +* +*Exit: +* Success - return pointer to user's function. +* Error - return NULL pointer. +* +*Notes: +* This routine depends on the behavior of _initterm() in CRT0DAT.C. +* Specifically, _initterm() must not skip the address pointed to by +* its first parameter, and must also stop before the address pointed +* to by its second parameter. This is because *pbegin will point +* to a valid address, and *pend will point at an invalid address. +* +*Exceptions: +* +*******************************************************************************/ + +_onexit_t _CALLTYPE1 __dllonexit ( + _onexit_t func, + PF ** pbegin, + PF ** pend + ) +{ + PF *p; + +#ifdef MTHREAD + _lockexit(); /* lock the exit code */ +#endif + + /* + * First, make sure the table has room for a new entry + */ + if ( _msize((*pbegin)) <= (unsigned)((char *)(*pend) - + (char *)(*pbegin)) ) { + /* + * not enough room, try to grow the table + */ + if ( (p = (PF *) realloc((*pbegin), _msize((*pbegin)) + + ONEXITTBLINCR * sizeof(PF))) == NULL ) { + /* + * didn't work. don't do anything rash, just fail + */ +#ifdef MTHREAD + _unlockexit(); +#endif + + return NULL; + } + + /* + * update (*pend) and (*pbegin) + */ + (*pend) = p + ((*pend) - (*pbegin)); + (*pbegin) = p; + } + + /* + * Put the new entry into the table and update the end-of-table + * pointer. + */ + *((*pend)++) = (PF)func; + +#ifdef MTHREAD + _unlockexit(); +#endif + + return func; + +} +#endif /* CRTDLL */ diff --git a/private/crt32/misc/perror.c b/private/crt32/misc/perror.c new file mode 100644 index 000000000..9e41b1c7a --- /dev/null +++ b/private/crt32/misc/perror.c @@ -0,0 +1,78 @@ +/*** +*perror.c - print system error message +* +* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines perror() - print system error message +* System error message are indexed by errno; conforms to XENIX +* standard, with much compatability with 1983 uniforum draft standard. +* +*Revision History: +* 09-02-83 RN initial version +* 04-13-87 JCR added const to declaration +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 12-29-87 JCR Multi-thread support +* 05-31-88 PHG Merged DLL and normal versions +* 06-03-88 JCR Added <io.h> to so _write_lk evaluates correctly and +* added (char *)message casts to get rid of warnings +* 03-15-90 GJF Replace _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h>, removed #include <register.h> and fixed +* the copyright. Also, cleaned up the formatting a bit. +* 04-05-90 GJF Added #include <string.h>. +* 08-14-90 SBM Removed unneeded #include <errmsg.h> +* 10-04-90 GJF New-style function declarator. +* 08-26-92 GJF Include unistd.h for POSIX build. +* +*******************************************************************************/ + +#include <cruntime.h> +#ifdef _POSIX_ +#include <unistd.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syserr.h> +#include <os2dll.h> +#include <io.h> + +/*** +*void perror(message) - print system error message +* +*Purpose: +* prints user's error message, then follows it with ": ", then the system +* error message, then a newline. All output goes to stderr. If user's +* message is NULL or a null string, only the system error message is +* printer. If errno is weird, prints "Unknown error". +* +*Entry: +* const char *message - users message to prefix system error message +* +*Exit: +* Prints message; no return value. +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 perror ( + REG1 const char *message + ) +{ + REG2 int fh = 2; + + _lock_fh(fh); /* acquire file handle lock */ + + if (message && *message) + { + _write_lk(fh,(char *)message,strlen(message)); + _write_lk(fh,": ",2); + } + + message = _sys_err_msg( errno ); + _write_lk(fh,(char *)message,strlen(message)); + _write_lk(fh,"\n",1); + + _unlock_fh(fh); /* release file handle lock */ +} diff --git a/private/crt32/misc/ppc/chandler.c b/private/crt32/misc/ppc/chandler.c new file mode 100644 index 000000000..4badd7a1d --- /dev/null +++ b/private/crt32/misc/ppc/chandler.c @@ -0,0 +1,222 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + chandler.c + +Abstract: + + This module implements the C specific exception handler that provides + structured condition handling for the C language. + +Author: + + Modified for PowerPC by Rick Simpson 27-Sep-1993 + + + from MIPS version by David N. Cutler (davec) 11-Sep-1990 + +Environment: + + Any mode. + +Revision History: + + Tom Wood (twood) 1-Nov-1993 + Use __C_ExecuteExceptionFilter and __C_ExecuteTerminationHandler + previously deleted from the MIPS version. +--*/ + +#include "nt.h" + + +// +// Define procedure prototypes for exception filter and termination handler +// execution routines defined in jmpunwnd.s +// +LONG +__C_ExecuteExceptionFilter ( + PEXCEPTION_POINTERS ExceptionPointers, + EXCEPTION_FILTER ExceptionFilter, + ULONG EstablisherFrame + ); +VOID +__C_ExecuteTerminationHandler ( + BOOLEAN AbnormalTermination, + TERMINATION_HANDLER TerminationHandler, + ULONG EstablisherFrame + ); + +EXCEPTION_DISPOSITION +__C_specific_handler ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PDISPATCHER_CONTEXT DispatcherContext + ) + +/*++ + +Routine Description: + + This function scans the scope tables associated with the specified + procedure and calls exception and termination handlers as necessary. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + EstablisherFrame - Supplies a pointer to frame of the establisher function. + + ContextRecord - Supplies a pointer to a context record. + + DispatcherContext - Supplies a pointer to the exception dispatcher or + unwind dispatcher context. + +Return Value: + + If the exception is handled by one of the exception filter routines, then + there is no return from this routine and RtlUnwind is called. Otherwise, + an exception disposition value of continue execution or continue search is + returned. + +--*/ + +{ + + ULONG ControlPc; + EXCEPTION_FILTER ExceptionFilter; + EXCEPTION_POINTERS ExceptionPointers; + PRUNTIME_FUNCTION FunctionEntry; + ULONG Index; + PSCOPE_TABLE ScopeTable; + ULONG TargetPc; + TERMINATION_HANDLER TerminationHandler; + LONG Value; + + // + // Get address of where control left the establisher, the address of the + // function table entry that describes the function, and the address of + // the scope table. + // + + ControlPc = DispatcherContext->ControlPc; + FunctionEntry = DispatcherContext->FunctionEntry; + ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData); + + // + // If an unwind is not in progress, then scan the scope table and call + // the appropriate exception filter routines. Otherwise, scan the scope + // table and call the appropriate termination handlers using the target + // PC obtained from the context record. + // are called. + // + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { + + // + // Scan the scope table and call the appropriate exception filter + // routines. + // + + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) && + (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) { + + // + // Call the exception filter routine. + // + + ExceptionFilter = + (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress; + Value = __C_ExecuteExceptionFilter(&ExceptionPointers, + ExceptionFilter, + (ULONG)EstablisherFrame); + + // + // If the return value is less than zero, then dismiss the + // exception. Otherwise, if the value is greater than zero, + // then unwind to the target exception handler. Otherwise, + // continue the search for an exception filter. + // + + if (Value < 0) { + return ExceptionContinueExecution; + } else if (Value > 0) { + RtlUnwind(EstablisherFrame, + (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget, + ExceptionRecord, + (PVOID)ExceptionRecord->ExceptionCode); + } + } + } + + } else { + + // + // Scan the scope table and call the appropriate termination handler + // routines. + // + + TargetPc = ContextRecord->Iar; + for (Index = 0; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) { + + // + // If the target PC is within the same scope the control PC + // is within, then this is an uplevel goto out of an inner try + // scope or a long jump back into a try scope. Terminate the + // scan termination handlers. + // + // N.B. The target PC can be just beyond the end of the scope, + // in which case it is a leave from the scope. + // + + + if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) { + break; + + } else { + + // + // If the scope table entry describes an exception filter + // and the associated exception handler is the target of + // the unwind, then terminate the scan for termination + // handlers. Otherwise, if the scope table entry describes + // a termination handler, then record the address of the + // end of the scope as the new control PC address and call + // the termination handler. + // + + if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) { + if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) { + break; + } + + } else { + DispatcherContext->ControlPc = + ScopeTable->ScopeRecord[Index].EndAddress + 4; + TerminationHandler = + (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress; + __C_ExecuteTerminationHandler(TRUE, + TerminationHandler, + (ULONG)EstablisherFrame); + } + } + } + } + } + + // + // Continue search for exception or termination handlers. + // + + return ExceptionContinueSearch; +} diff --git a/private/crt32/misc/ppc/cinitone.s b/private/crt32/misc/ppc/cinitone.s new file mode 100644 index 000000000..f412234e0 --- /dev/null +++ b/private/crt32/misc/ppc/cinitone.s @@ -0,0 +1,41 @@ +// page ,132 +// title cinitone - C Run-Time Initialization for _onexit/atexit +// +// cinitone.asm - WIN32 C Run-Time Init for _onexit()/atexit() routines +// +// Copyright (c) 1992, Microsoft Corporation. All rights reserved. +// +// Purpose: +// Initialization entry for the _onexit()/atexit() functions. +// This module adds an entry for _onexitinit() to the initializer table. +// ONEXIT.C references the dummy variable __c_onexit in order to force +// the loading of this module. +// +// Notes: +// +// Revision History: +// 03-19-92 SKS Module created. +// 03-24-92 SKS Added MIPS support (NO_UNDERSCORE) +// 04-30-92 SKS Add "offset FLAT:" to get correct fixups for OMF objs +// 08-06-92 SKS Revised to use new section names and macros +// +// ***************************************************************************** + +#include "kxppc.h" + + .extern _onexitinit + +beginSection(XIC) + + .long _onexitinit + +endSection(XIC) + + + .data + .align 2 + + .globl __c_onexit + +__c_onexit: .long 0 + diff --git a/private/crt32/misc/ppc/jmpuwind.s b/private/crt32/misc/ppc/jmpuwind.s new file mode 100644 index 000000000..dcd129f29 --- /dev/null +++ b/private/crt32/misc/ppc/jmpuwind.s @@ -0,0 +1,162 @@ +//++ +// +// Copyright (c) 1992 Microsoft Corporation +// +// Module Name: +// +// jmpuwind.s +// +// Abstract: +// +// This module implements the MIPS specific routine to jump to the runtime +// time library unwind routine. +// +// Author: +// +// David N. Cutler (davec) 12-Sep-1990 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Tom Wood (twood) 1-Nov-1993 +// Added __C_ExecuteExceptionFilter and __C_ExecuteTerminationHandler +// previously deleted from the MIPS version. +//-- + +//list(off) +#include "ksppc.h" +//list(on) + .extern ..RtlUnwind + +// +// Define the call frame for calling the exception filter and termination +// handler. +// + .struct 0 +CfBackChain: .space 4 // chain to previous call frame +CfSavedR31: .space 4 // glue-saved register +CfSavedRtoc: .space 4 // glue-saved register + .space 3*4 // remaining part of the frame header +//++ +// +// ULONG +// __C_ExecuteExceptionFilter ( +// PEXCEPTION_POINTERS ExceptionPointers, +// EXCEPTION_FILTER ExceptionFilter, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function calls the specified exception filter routine with the +// establisher environment passed in the TOC register. +// +// Arguments: +// +// ExceptionPointers (r.3) - Supplies a pointer to the exception pointers +// structure. +// +// ExceptionFilter (r.4) - Supplies the address of the exception filter +// routine. +// +// EstablisherFrame (r.5) - Supplies the establisher frame pointer. +// +// Return Value: +// +// The value returned by the exception filter routine. +// +//-- + SPECIAL_ENTRY(__C_ExecuteExceptionFilter) + stw r.31, CfSavedR31 (r.sp) // save r.31 before using it. + mtctr r.4 // get ready to call the filter. + mflr r.31 // save the link register in r.31. + stw r.toc, CfSavedRtoc (r.sp) // save r.toc + PROLOGUE_END(__C_ExecuteExceptionFilter) + or r.toc,r.5,r.5 // pass the establisher environment in r.toc + bctrl // branch and link to the filter. + mtlr r.31 // get ready to return + lwz r.31, CfSavedR31 (r.sp) // restore r.31 + lwz r.toc, CfSavedRtoc (r.sp) // restore r.toc + SPECIAL_EXIT(__C_ExecuteExceptionFilter) + +//++ +// +// VOID +// __C_ExecuteTerminationHandler ( +// BOOLEAN AbnormalTermination, +// TERMINATION_HANDLER TerminationHandler, +// ULONG EstablisherFrame +// ) +// +// Routine Description: +// +// This function calls the specified termination handler routine with the +// establisher environment passed in the TOC register. +// +// Arguments: +// +// AbnormalTermination (r.3) - Supplies a boolean value that determines +// whether the termination is abnormal. +// +// TerminationHandler (r.4) - Supplies the address of the termination +// handler routine. +// +// EstablisherFrame (r.5) - Supplies the establisher frame pointer. +// +// Return Value: +// +// None. +// +//-- + SPECIAL_ENTRY(__C_ExecuteTerminationHandler) + stw r.31, CfSavedR31 (r.sp) // save r.31 before using it. + mtctr r.4 // get ready to call the filter. + mflr r.31 // save the link register in r.31. + stw r.toc, CfSavedRtoc (r.sp) // save r.toc + PROLOGUE_END(__C_ExecuteTerminationHandler) + or r.toc,r.5,r.5 // pass the establisher environment in r.toc + bctrl // branch and link to the filter. + mtlr r.31 // get ready to return + lwz r.31, CfSavedR31 (r.sp) // restore r.31 + lwz r.toc, CfSavedRtoc (r.sp) // restore r.toc + SPECIAL_EXIT(__C_ExecuteTerminationHandler) + +//++ +// +// VOID +// __jump_unwind ( +// IN PVOID EstablishFrame, +// IN PVOID TargetPc +// ) +// +// Routine Description: +// +// This function transfer control to unwind. It is used by the MIPS +// compiler when a goto out of the body or a try statement occurs. +// +// Arguments: +// +// EstablishFrame (r.3) - Supplies the establisher frame pointer of the +// target of the unwind. +// +// TargetPc (r.4) - Supplies the target instruction address where control +// is to be transfered to after the unwind operation is complete. +// +// Return Value: +// +// None. +// +//-- + + NESTED_ENTRY (__jump_unwind, STK_MIN_FRAME+8, 0, 0) + PROLOGUE_END(__jump_unwind) + + li r.5, 0 // set NULL exception record address + li r.6, 0 // set destination return value + bl ..RtlUnwind // unwind to specified target + .znop ..RtlUnwind + + NESTED_EXIT (__jump_unwind, STK_MIN_FRAME+8, 0, 0) diff --git a/private/crt32/misc/ppc/longjmp.s b/private/crt32/misc/ppc/longjmp.s new file mode 100644 index 000000000..d5149f869 --- /dev/null +++ b/private/crt32/misc/ppc/longjmp.s @@ -0,0 +1,143 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation and Microsoft Corporation +// +// Module Name: +// +// longjmp.s +// +// Abstract: +// +// This module implements the MIPS specific routine to perform a long +// jump operation. +// +// N.B. This routine conditionally provides UNSAFE handling of longjmp +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an unitialized variable +// has been set to a nonzero value. +// +// Author: +// +// Rick Simpson 13-Oct-1993 +// +// based on MIPS version by David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +//list(off) +#include "ksppc.h" +//list(on) + .extern ..RtlUnwind + +//++ +// +// int +// longjmp ( +// IN jmp_buf JumpBuffer, +// IN int ReturnValue +// ) +// +// Routine Description: +// +// This function performs a long jump to the context specified by the +// jump buffer. +// +// Arguments: +// +// JumpBuffer (r.3) - Supplies the address of a jump buffer that contains +// jump information. +// +// ReturnValue (r.4) - Supplies the value that is to be returned to the +// caller of setjmp(). +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY (longjmp) + + cmpwi cr.0, r.4, 0 // check return value for 0 + lwz r.0, JbType (r.3) // load safe/unsafe switch + cmpwi cr.1, r.0, 0 // check for unsafe + bne cr.0, Lj10 // branch if not trying to return 0 + li r.4, 1 // force return value to be non-zero +Lj10: bne cr.1, ...Lj20 // branch if safe form of setjmp/longjmp + +// +// Provide unsafe handling of longjmp. +// + + lfd f.14, JbFpr14 (r.3) // reload n-v floating point regs + lfd f.15, JbFpr15 (r.3) + lfd f.16, JbFpr16 (r.3) + lfd f.17, JbFpr17 (r.3) + lfd f.18, JbFpr18 (r.3) + lfd f.19, JbFpr19 (r.3) + lfd f.20, JbFpr20 (r.3) + lfd f.21, JbFpr21 (r.3) + lfd f.22, JbFpr22 (r.3) + lfd f.23, JbFpr23 (r.3) + lfd f.24, JbFpr24 (r.3) + lfd f.25, JbFpr25 (r.3) + lfd f.26, JbFpr26 (r.3) + lfd f.27, JbFpr27 (r.3) + lfd f.28, JbFpr28 (r.3) + lfd f.29, JbFpr29 (r.3) + lfd f.30, JbFpr30 (r.3) + lfd f.31, JbFpr31 (r.3) + + lwz r.13, JbGpr13 (r.3) // reload n-v general regs + lwz r.14, JbGpr14 (r.3) + lwz r.15, JbGpr15 (r.3) + lwz r.16, JbGpr16 (r.3) + lwz r.17, JbGpr17 (r.3) + lwz r.18, JbGpr18 (r.3) + lwz r.19, JbGpr19 (r.3) + lwz r.20, JbGpr20 (r.3) + lwz r.21, JbGpr21 (r.3) + lwz r.22, JbGpr22 (r.3) + lwz r.23, JbGpr23 (r.3) + lwz r.24, JbGpr24 (r.3) + lwz r.25, JbGpr25 (r.3) + lwz r.26, JbGpr26 (r.3) + lwz r.27, JbGpr27 (r.3) + lwz r.28, JbGpr28 (r.3) + lwz r.29, JbGpr29 (r.3) + lwz r.30, JbGpr30 (r.3) + lwz r.31, JbGpr31 (r.3) + + lwz r.5, JbIar (r.3) // get setjmp return address + lwz r.6, JbCr (r.3) // get saved CR + mtlr r.5 // return addr -> LR + lwz r.1, JbGpr1 (r.3) // restore stack pointer + lwz r.2, JbGpr2 (r.3) // restore TOC pointer + mtcrf 0xff,r.6 // saved CR -> CR + mr r.3, r.4 // return value from longjmp() + blr // jump back to setjmp() site + + DUMMY_EXIT (longjmp) + + +// +// Provide safe handling of longjmp. +// + + NESTED_ENTRY(.Lj20, STK_MIN_FRAME+8, 0, 0) + PROLOGUE_END(.Lj20) + + mr r.6, r.4 // set return value (4th arg) + li r.5, 0 // set exception record address (3rd arg) + lwz r.4, 4 (r.3) // set target instr address (2nd arg) + lwz r.3, 0 (r.3) // set target frame address (1st arg) + bl ..RtlUnwind // finish in common code + .znop ..RtlUnwind + + NESTED_EXIT(.Lj20, STK_MIN_FRAME+8, 0, 0) diff --git a/private/crt32/misc/ppc/miscasm.s b/private/crt32/misc/ppc/miscasm.s new file mode 100644 index 000000000..8fab2f64e --- /dev/null +++ b/private/crt32/misc/ppc/miscasm.s @@ -0,0 +1,273 @@ +// +// Miscellaneous assembly-language routines and data for +// PowerPC RTL +// +#include "ksppc.h" +// +// Copyright 1993 IBM Corporation +// +// By Rick Simpson, 17 August 1993 +// +//----------------------------------------------------------------------------- +// +// These routines save and restore only the GPRs and FPRs. +// +// Saving and restoring of other non-volatile registers (LR, certain +// fields of CR) is the responsibility of in-line prologue and epilogue +// code. +// +//----------------------------------------------------------------------------- +// +// _savegpr_<n> +// Inputs: +// r12 = pointer to END of GPR save area +// LR = return address to invoking prologue +// Saves GPR<n> through GPR31 in area preceeding where r12 points +// +// _savefpr_<n> +// Inputs: +// r1 = pointer to stack frame header +// LR = return address to invoking prologue +// Saves FPR<m> through FPR31 in area preceeding stack frame header +// +//----------------------------------------------------------------------------- +// +// _restgpr_<n> +// Inputs: +// r12 = pointer to END of GPR save area +// LR = return address to invoking prologue +// Restores GPR<n> through GPR31 from area preceeding where r12 points +// +// _restfpr_<m> +// Inputs: +// r1 = pointer to stack frame header +// LR = return address to invoking prologue +// Restores FPR<m> through FPR31 from area preceeding stack frame header +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// _savegpr_<n> -- Save GPRs when FPRs are also saved +// +// On entry: +// r12 = address of END of GPR save area +// LR = return address to prologue +// +// Saves GPR<n> through GPR31 in area preceeding where r12 points +// +//----------------------------------------------------------------------------- + + FN_TABLE(_savegpr_13,0,1) + DUMMY_ENTRY(_savegpr_13) + .set _savegpr_13.body,.._savegpr_13-1 + stw r13, -4*(32-13)(r12) + DUMMY_ENTRY(_savegpr_14) + stw r14, -4*(32-14)(r12) + DUMMY_ENTRY(_savegpr_15) + stw r15, -4*(32-15)(r12) + DUMMY_ENTRY(_savegpr_16) + stw r16, -4*(32-16)(r12) + DUMMY_ENTRY(_savegpr_17) + stw r17, -4*(32-17)(r12) + DUMMY_ENTRY(_savegpr_18) + stw r18, -4*(32-18)(r12) + DUMMY_ENTRY(_savegpr_19) + stw r19, -4*(32-19)(r12) + DUMMY_ENTRY(_savegpr_20) + stw r20, -4*(32-20)(r12) + DUMMY_ENTRY(_savegpr_21) + stw r21, -4*(32-21)(r12) + DUMMY_ENTRY(_savegpr_22) + stw r22, -4*(32-22)(r12) + DUMMY_ENTRY(_savegpr_23) + stw r23, -4*(32-23)(r12) + DUMMY_ENTRY(_savegpr_24) + stw r24, -4*(32-24)(r12) + DUMMY_ENTRY(_savegpr_25) + stw r25, -4*(32-25)(r12) + DUMMY_ENTRY(_savegpr_26) + stw r26, -4*(32-26)(r12) + DUMMY_ENTRY(_savegpr_27) + stw r27, -4*(32-27)(r12) + DUMMY_ENTRY(_savegpr_28) + stw r28, -4*(32-28)(r12) + DUMMY_ENTRY(_savegpr_29) + stw r29, -4*(32-29)(r12) + DUMMY_ENTRY(_savegpr_30) + stw r30, -4*(32-30)(r12) + DUMMY_ENTRY(_savegpr_31) + stw r31, -4*(32-31)(r12) + SPECIAL_EXIT(_savegpr_13) + +//----------------------------------------------------------------------------- +// +// _savefpr_<n> -- Saves FPRs +// +// On entry: +// r1 = pointer to stack frame header +// LR = return address to prologue +// +// Saves FPR<n> through FPR31 in area preceeding stack frame header +// +//----------------------------------------------------------------------------- + + FN_TABLE(_savefpr_14,0,1) + DUMMY_ENTRY(_savefpr_14) + .set _savefpr_14.body,.._savefpr_14-1 + stfd f14, -8*(32-14)(r1) + DUMMY_ENTRY(_savefpr_15) + stfd f15, -8*(32-15)(r1) + DUMMY_ENTRY(_savefpr_16) + stfd f16, -8*(32-16)(r1) + DUMMY_ENTRY(_savefpr_17) + stfd f17, -8*(32-17)(r1) + DUMMY_ENTRY(_savefpr_18) + stfd f18, -8*(32-18)(r1) + DUMMY_ENTRY(_savefpr_19) + stfd f19, -8*(32-19)(r1) + DUMMY_ENTRY(_savefpr_20) + stfd f20, -8*(32-20)(r1) + DUMMY_ENTRY(_savefpr_21) + stfd f21, -8*(32-21)(r1) + DUMMY_ENTRY(_savefpr_22) + stfd f22, -8*(32-22)(r1) + DUMMY_ENTRY(_savefpr_23) + stfd f23, -8*(32-23)(r1) + DUMMY_ENTRY(_savefpr_24) + stfd f24, -8*(32-24)(r1) + DUMMY_ENTRY(_savefpr_25) + stfd f25, -8*(32-25)(r1) + DUMMY_ENTRY(_savefpr_26) + stfd f26, -8*(32-26)(r1) + DUMMY_ENTRY(_savefpr_27) + stfd f27, -8*(32-27)(r1) + DUMMY_ENTRY(_savefpr_28) + stfd f28, -8*(32-28)(r1) + DUMMY_ENTRY(_savefpr_29) + stfd f29, -8*(32-29)(r1) + DUMMY_ENTRY(_savefpr_30) + stfd f30, -8*(32-30)(r1) + DUMMY_ENTRY(_savefpr_31) + stfd f31, -8*(32-31)(r1) + SPECIAL_EXIT(_savefpr_14) + +//----------------------------------------------------------------------------- +// +// _restgpr_<n> -- Restore GPRs when FPRs are also restored +// +// On entry: +// r12 = address of END of GPR save area +// LR = return address +// +// Restores GPR<n> through GPR31 from area preceeding where r12 points +// +//----------------------------------------------------------------------------- + + FN_TABLE(_restgpr_13,0,2) + DUMMY_ENTRY(_restgpr_13) + .set _restgpr_13.body,.._restgpr_13-2 + lwz r13, -4*(32-13)(r12) + DUMMY_ENTRY(_restgpr_14) + lwz r14, -4*(32-14)(r12) + DUMMY_ENTRY(_restgpr_15) + lwz r15, -4*(32-15)(r12) + DUMMY_ENTRY(_restgpr_16) + lwz r16, -4*(32-16)(r12) + DUMMY_ENTRY(_restgpr_17) + lwz r17, -4*(32-17)(r12) + DUMMY_ENTRY(_restgpr_18) + lwz r18, -4*(32-18)(r12) + DUMMY_ENTRY(_restgpr_19) + lwz r19, -4*(32-19)(r12) + DUMMY_ENTRY(_restgpr_20) + lwz r20, -4*(32-20)(r12) + DUMMY_ENTRY(_restgpr_21) + lwz r21, -4*(32-21)(r12) + DUMMY_ENTRY(_restgpr_22) + lwz r22, -4*(32-22)(r12) + DUMMY_ENTRY(_restgpr_23) + lwz r23, -4*(32-23)(r12) + DUMMY_ENTRY(_restgpr_24) + lwz r24, -4*(32-24)(r12) + DUMMY_ENTRY(_restgpr_25) + lwz r25, -4*(32-25)(r12) + DUMMY_ENTRY(_restgpr_26) + lwz r26, -4*(32-26)(r12) + DUMMY_ENTRY(_restgpr_27) + lwz r27, -4*(32-27)(r12) + DUMMY_ENTRY(_restgpr_28) + lwz r28, -4*(32-28)(r12) + DUMMY_ENTRY(_restgpr_29) + lwz r29, -4*(32-29)(r12) + DUMMY_ENTRY(_restgpr_30) + lwz r30, -4*(32-30)(r12) + DUMMY_ENTRY(_restgpr_31) + lwz r31, -4*(32-31)(r12) + SPECIAL_EXIT(_restgpr_13) + +//----------------------------------------------------------------------------- +// +// _restfpr_<n> -- Restores FPRs +// +// On entry: +// r1 = pointer to stack frame header +// LR = return address +// +// Restores FPR<n> through FPR31 from area preceeding stack frame header +// +//----------------------------------------------------------------------------- + + FN_TABLE(_restfpr_14,0,2) + DUMMY_ENTRY(_restfpr_14) + .set _restfpr_14.body,.._restfpr_14-2 + lfd f14, -8*(32-14)(r1) + DUMMY_ENTRY(_restfpr_15) + lfd f15, -8*(32-15)(r1) + DUMMY_ENTRY(_restfpr_16) + lfd f16, -8*(32-16)(r1) + DUMMY_ENTRY(_restfpr_17) + lfd f17, -8*(32-17)(r1) + DUMMY_ENTRY(_restfpr_18) + lfd f18, -8*(32-18)(r1) + DUMMY_ENTRY(_restfpr_19) + lfd f19, -8*(32-19)(r1) + DUMMY_ENTRY(_restfpr_20) + lfd f20, -8*(32-20)(r1) + DUMMY_ENTRY(_restfpr_21) + lfd f21, -8*(32-21)(r1) + DUMMY_ENTRY(_restfpr_22) + lfd f22, -8*(32-22)(r1) + DUMMY_ENTRY(_restfpr_23) + lfd f23, -8*(32-23)(r1) + DUMMY_ENTRY(_restfpr_24) + lfd f24, -8*(32-24)(r1) + DUMMY_ENTRY(_restfpr_25) + lfd f25, -8*(32-25)(r1) + DUMMY_ENTRY(_restfpr_26) + lfd f26, -8*(32-26)(r1) + DUMMY_ENTRY(_restfpr_27) + lfd f27, -8*(32-27)(r1) + DUMMY_ENTRY(_restfpr_28) + lfd f28, -8*(32-28)(r1) + DUMMY_ENTRY(_restfpr_29) + lfd f29, -8*(32-29)(r1) + DUMMY_ENTRY(_restfpr_30) + lfd f30, -8*(32-30)(r1) + DUMMY_ENTRY(_restfpr_31) + lfd f31, -8*(32-31)(r1) + SPECIAL_EXIT(_restfpr_14) + +// +// This is a copy of the function table entries for the millicode. It's +// used with the PPCKD_SYMBOL_SEARCH mechanism in vunwind.c to allow +// for older versions of miscasm.obj. +// + + .reldata + .globl _millicode_table +_millicode_table: + .long .._savegpr_13, _savegpr_13.end, 0, 1, .._savegpr_13 + .long .._savefpr_14, _savefpr_14.end, 0, 1, .._savefpr_14 + .long .._restgpr_13, _restgpr_13.end, 0, 2, .._restgpr_13 + .long .._restfpr_14, _restfpr_14.end, 0, 2, .._restfpr_14 diff --git a/private/crt32/misc/ppc/setjmp.s b/private/crt32/misc/ppc/setjmp.s new file mode 100644 index 000000000..65b58adf5 --- /dev/null +++ b/private/crt32/misc/ppc/setjmp.s @@ -0,0 +1,138 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation and Microsoft Corporation +// +// Module Name: +// +// setjmp.s +// +// Abstract: +// +// This module implements the MIPS specific routine to perform a setjmp. +// +// N.B. This module conditionally provides UNSAFE handling of setjmp and +// which is NOT integrated with structured exception handling. The +// determination is made based on whether an uninitialized variable +// has been set to a nonzero value. +// +// Author: +// +// Rick Simpson 13-Oct-1993 +// +// based on MIPS version by David N. Cutler (davec) 7-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +//list(off) +#include "ksppc.h" +//list(on) + +// +// Define variable that will cause setjmp/longjmp to be safe or unsafe with +// respect to structured exception handling. +// + + .globl _setjmpexused + .comm _setjmpexused , 4 + +//++ +// +// int +// setjmp ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function saved the current nonvolatile register state in the +// specified jump buffer and returns a function vlaue of zero. +// +// Arguments: +// +// JumpBuffer (r.3) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + + LEAF_ENTRY (setjmp) + +// +// If _setjmpexused is non-NULL, it contains the entry point address +// of the safe version of setjmp, ..setjmpex. We branch thru the CTR +// using this variable rather than branching directly to the entry point +// to avoid assembling a hard reference to ..setjmpex into this code. +// CTR is used to avoid killing caller's LR. +// + + lwz r.4, [toc] _setjmpexused (r.toc) // get address of switch variable + lwz r.0, 0 (r.4) // get value of switch variable + cmpwi r.0, 0 // see if switch is NULL + mtctr r.0 // if switch is non-NULL, + bnectr // branch to safe setjmp() routine + +// +// Provide unsafe handling of setjmp. +// + + mflr r.0 // fetch incoming LR + mfcr r.4 // fetch incoming CR + + stfd f.14, JbFpr14 (r.3) // save n-v floating point regs + stfd f.15, JbFpr15 (r.3) + stfd f.16, JbFpr16 (r.3) + stfd f.17, JbFpr17 (r.3) + stfd f.18, JbFpr18 (r.3) + stfd f.19, JbFpr19 (r.3) + stfd f.20, JbFpr20 (r.3) + stfd f.21, JbFpr21 (r.3) + stfd f.22, JbFpr22 (r.3) + stfd f.23, JbFpr23 (r.3) + stfd f.24, JbFpr24 (r.3) + stfd f.25, JbFpr25 (r.3) + stfd f.26, JbFpr26 (r.3) + stfd f.27, JbFpr27 (r.3) + stfd f.28, JbFpr28 (r.3) + stfd f.29, JbFpr29 (r.3) + stfd f.30, JbFpr30 (r.3) + stfd f.31, JbFpr31 (r.3) + + stw r.13, JbGpr13 (r.3) // save n-v general regs + stw r.14, JbGpr14 (r.3) + stw r.15, JbGpr15 (r.3) + stw r.16, JbGpr16 (r.3) + stw r.17, JbGpr17 (r.3) + stw r.18, JbGpr18 (r.3) + stw r.19, JbGpr19 (r.3) + stw r.20, JbGpr20 (r.3) + stw r.21, JbGpr21 (r.3) + stw r.22, JbGpr22 (r.3) + stw r.23, JbGpr23 (r.3) + stw r.24, JbGpr24 (r.3) + stw r.25, JbGpr25 (r.3) + stw r.26, JbGpr26 (r.3) + stw r.27, JbGpr27 (r.3) + stw r.28, JbGpr28 (r.3) + stw r.29, JbGpr29 (r.3) + stw r.30, JbGpr30 (r.3) + stw r.31, JbGpr31 (r.3) + + stw r.0, JbIar (r.3) // setjmp return address + stw r.4, JbCr (r.3) // save CR (n-v part) + stw r.sp, JbGpr1 (r.3) // save stack pointer + stw r.toc, JbGpr2 (r.3) // save TOC pointer + li r.0, 0 + stw r.0, JbType (r.3) // clean safe setjmp flag + + li r.3, 0 // set return value + LEAF_EXIT (setjmp) // return + diff --git a/private/crt32/misc/ppc/setjmpex.s b/private/crt32/misc/ppc/setjmpex.s new file mode 100644 index 000000000..063f8fa68 --- /dev/null +++ b/private/crt32/misc/ppc/setjmpex.s @@ -0,0 +1,194 @@ +//++ +// +// Copyright (c) 1993 IBM Corporation and Microsoft Corporation +// +// Module Name: +// +// setjmpex.s +// +// Abstract: +// +// This module implements the MIPS specific routine to provide SAFE +// handling of setjmp/longjmp with respect to structured exception +// handling. +// +// Author: +// +// Rick Simpson 13-Oct-1993 +// +// based on MIPS version by David N. Cutler (davec) 2-Apr-1993 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +// Tom Wood 23-Aug-1994 +// Add stack limit parameters to RtlVirtualUnwind. +//-- + +//list(off) +#include "ksppc.h" +//list(on) + .extern ..RtlLookupFunctionEntry + .extern ..RtlVirtualUnwind + +// +// Define variable that will cause setjmp/longjmp to be safe with respect +// to structured exception handling. +// + + .globl _setjmpexused + .data +_setjmpexused: + .long .._setjmpex // set address of safe setjmp routine + +//++ +// +// int +// _setjmpex ( +// IN jmp_buf JumpBuffer +// ) +// +// Routine Description: +// +// This function transfers control to the actual setjmp routine. +// +// Arguments: +// +// JumpBuffer (r.3) - Supplies the address of a jump buffer to store the +// jump information. +// +// Return Value: +// +// A value of zero is returned. +// +//-- + +// Stack frame definition: + + .struct 0 +SjBackChain: .space 4 // chain to previous stack frame + .space 5*4 // rest of standard stack frame header + + .space 8*4 // standard outgoing arg area + + .align 3 // ensure 8-byte boundary +SjCtxt: .space ContextFrameLength // context frame + +SjFl: .space 4 // in function flag variable + + .align 3 // ensure that overall length + // will be a multiple of 8 +SjReturnAddr: .space 4 // space for saved LR (prologue will + // store it here) + .space 4 // space for saved r.31 +SetjmpFrameLength: + + + + NESTED_ENTRY (_setjmpex,SetjmpFrameLength,1,0) + + PROLOGUE_END (_setjmpex) + +// +// Save the nonvolatile machine state in the context record +// + + // skip Fprs as all we are really trying to do here is prime the + // pump for RtlVirtualUnwind. + + stw r.13, CxGpr13 + SjCtxt (r.sp) // save n-v general regs + stw r.14, CxGpr14 + SjCtxt (r.sp) + stw r.15, CxGpr15 + SjCtxt (r.sp) + stw r.16, CxGpr16 + SjCtxt (r.sp) + stw r.17, CxGpr17 + SjCtxt (r.sp) + stw r.18, CxGpr18 + SjCtxt (r.sp) + stw r.19, CxGpr19 + SjCtxt (r.sp) + stw r.20, CxGpr20 + SjCtxt (r.sp) + stw r.21, CxGpr21 + SjCtxt (r.sp) + stw r.22, CxGpr22 + SjCtxt (r.sp) + stw r.23, CxGpr23 + SjCtxt (r.sp) + stw r.24, CxGpr24 + SjCtxt (r.sp) + stw r.25, CxGpr25 + SjCtxt (r.sp) + stw r.26, CxGpr26 + SjCtxt (r.sp) + stw r.27, CxGpr27 + SjCtxt (r.sp) + stw r.28, CxGpr28 + SjCtxt (r.sp) + stw r.29, CxGpr29 + SjCtxt (r.sp) + stw r.30, CxGpr30 + SjCtxt (r.sp) + stw r.31, CxGpr31 + SjCtxt (r.sp) + + mr r.31, r.3 // save incoming jump buffer pointer + + lwz r.3, SjReturnAddr (r.sp) // pick up return addr to caller + la r.0, SetjmpFrameLength (r.sp) // save caller's stack frame pointer + stw r.0, CxGpr1 + SjCtxt (r.sp) + stw r.3, CxIar + SjCtxt (r.sp) // save resume addr in context + stw r.3, 4 (r.31) // save resume addr in 2nd word of jmpbuf + stw r.sp, JbType (r.31) // set "safe setjmp" flag in jump buffer + +// +// Perform unwind to determine the virtual frame pointer of the caller. +// + subi r.3, r.3, 4 // compute control PC address + bl ..RtlLookupFunctionEntry // lookup function table address + .znop ..RtlLookupFunctionEntry + + mr r.4, r.3 // set returned value as 2nd arg + lwz r.3, SjReturnAddr (r.sp) // pick up return address again + la r.5, SjCtxt (r.sp) // context record addr is 3rd arg + la r.6, SjFl (r.sp) // addr of in-func flag is 4th arg + subi r.3, r.3, 4 // compute control PC address as 1st arg + mr r.7, r.31 // addr of 1st word of jmpbuf is 5th arg + // (virt frame pointer will be stored here) + li r.8, 0 // ctxt pointers (NULL) is 6th arg + li r.9, 0 // low stack limit is 7th arg + li r.10, -1 // high stack limit is 8th arg + bl ..RtlVirtualUnwind // compute virtual frame pointer value + .znop ..RtlVirtualUnwind + +// +// If we were called via a thunk the Establisher Frame derived by +// RtlVirtualUnwind will be equal to the current stack frame. If +// this is the case we need to unwind one more level, also, the +// ControlPc returned by RtlVirtualUnwind (+4) should be used as +// the resume address. +// +// Note: this requirement will go away if we adopt the glue proposal +// that returns directly to the caller (caller reloades toc). +// (plj 3/26/94) + + lwz r.7, 0(r.31) // Establisher Frame + addi r.8, r.sp, SetjmpFrameLength // caller's sp + cmplw r.7, r.8 + bne SjDone + + // Save returned value (+4) as resume address in jump buffer + + addi r.8, r.3, 4 + stw r.8, 4(r.31) + + // Unwind one more level to get the "real" establisher frame. + + bl ..RtlLookupFunctionEntry // lookup function table address + .znop ..RtlLookupFunctionEntry + + mr r.4, r.3 // set returned value as 2nd arg + lwz r.3, 4(r.31) // pick up ControlPc again + la r.5, SjCtxt(r.sp) // &context record + la r.6, SjFl(r.sp) // addr of in-func flag + mr r.7, r.31 // & 1st word of jmpbuf + li r.8, 0 // ctxt pointers (NULL) + li r.9, 0 // low stack limit + li r.10, -1 // high stack limit + subi r.3, r.3, 4 // unadjust ControlPc + bl ..RtlVirtualUnwind // compute & frame pointer + .znop ..RtlVirtualUnwind +// +// Set return value, restore registers, deallocate stack frame, and return. +// + +SjDone: + li r.3, 0 // set return value of 0 + NESTED_EXIT (_setjmpex,SetjmpFrameLength,1,0) diff --git a/private/crt32/misc/ppc/sources b/private/crt32/misc/ppc/sources new file mode 100644 index 000000000..520ce611c --- /dev/null +++ b/private/crt32/misc/ppc/sources @@ -0,0 +1,6 @@ +PPC_SOURCES=ppc\chandler.c \ + ppc\setjmp.s \ + ppc\setjmpex.s \ + ppc\longjmp.s \ + ppc\jmpuwind.s \ + ppc\miscasm.s diff --git a/private/crt32/misc/purevirt.c b/private/crt32/misc/purevirt.c new file mode 100644 index 000000000..14743f517 --- /dev/null +++ b/private/crt32/misc/purevirt.c @@ -0,0 +1,42 @@ +/*** +*purevirt.c - stub to trap pure virtual function calls +* +* Copyright (c) 1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _purecall() - +* +*Revision History: +* 09-30-92 GJF Module created +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <internal.h> +#include <rterr.h> + +/*** +*void _purecall(void) - +* +*Purpose: +* +*Entry: +* No arguments +* +*Exit: +* Never returns +* +*Exceptions: +* +*******************************************************************************/ + +void _CRTAPI1 _purecall( + void + ) +{ + _amsg_exit(_RT_PUREVIRT); +} + +#endif diff --git a/private/crt32/misc/putenv.c b/private/crt32/misc/putenv.c new file mode 100644 index 000000000..0e74fcbb5 --- /dev/null +++ b/private/crt32/misc/putenv.c @@ -0,0 +1,453 @@ +/*** +*putenv.c - put an environment variable into the environment +* +* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _putenv() - adds a new variable to environment; does not +* change global environment, only the process' environment. +* +*Revision History: +* 08-08-84 RN initial version +* 02-23-88 SKS check for environment containing only the NULL string +* 05-31-88 PHG Merged DLL and normal versions +* 07-14-88 JCR Much simplified since (1) __setenvp always uses heap, and +* (2) envp array and env strings are in seperate heap blocks +* 07-03-89 PHG Now "option=" string removes string from environment +* 08-17-89 GJF Removed _NEAR_, _LOAD_DS and fixed indents. +* 09-14-89 KRS Don't give error if 'option' not defined in "option=". +* 11-20-89 GJF Added const to arg type. Also, fixed copyright. +* 03-15-90 GJF Made the calling type _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 04-05-90 GJF Made findenv() _CALLTYPE4. +* 04-26-90 JCR Bug fix if environ is NULL (stubbed out _setenvp) +* 07-25-90 SBM Removed redundant include (stdio.h) +* 10-04-90 GJF New-style function declarators. +* 01-21-91 GJF ANSI naming. +* 02-06-91 SRW Added _WIN32_ conditional for SetEnvironmentVariable +* 02-18-91 SRW Changed _WIN32_ conditional for SetEnvironmentVariable +* to be in addition to old logic instead of replacement +* 04-23-92 GJF Made findenv insensitive to the case of name for Win32. +* Also added support for 'current drive' environment +* strings in Win32. +* 04-29-92 GJF Repackaged so that _putenv_lk could be easily added for +* for Win32. +* 05-05-92 DJM POSIX not supported. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <errno.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> +#include <internal.h> +#include <os2dll.h> +#include <memory.h> +#include <oscalls.h> + +static int _CALLTYPE4 findenv(const char *name, int len); + + +#ifdef _CRUISER_ + +/*** +*int _putenv(option) - add/replace/remove variable in environment +* +*Purpose: +* option should be of the form "option=value". If a string with the +* given option part already exists, it is replaced with the given +* string; otherwise the given string is added to the environment. +* If the string is of the form "option=", then the string is +* removed from the environment, if it exists. If the string has +* no equals sign, error is returned. +* +*Entry: +* char *option - option string to set in the environment list. +* should be of the form "option=value". +* +*Exit: +* returns 0 if OK, -1 if fails. +* +*Exceptions: +* +*Warning: +* This code will not work if variables are removed from the +* environment by deleting them from environ[]. Use _putenv("option=") +* to remove a variable. +* +*******************************************************************************/ + +int _CALLTYPE1 _putenv ( + REG3 const char *option + ) +{ + REG1 char **env; + REG4 const char *equal; + REG2 int ix; + int remove; /* 1 means remove string from environment */ + + if (!option) + return(-1); + + _mlock( _ENV_LOCK ); + + /* find the equal sign to delimit the name being searched for. + * If no equal sign, then return error + */ + + for (equal = option; *equal != '='; equal++) + if (*equal == '\0') + goto unlock_error; + + /* see if removing or adding */ + remove = (equal[1] == '\0'); + + /* see if _environ array exists */ + if (_environ == NULL) { + if (remove) + goto unlock_good; + else { + /* get an array and init it to NULL */ + if ( (_environ = malloc(sizeof(void *))) == NULL) + goto unlock_error; + *_environ = NULL; + } + } + + /* init env pointer */ + + env = _environ; + + /* See if the string is already in the environment */ + + ix = findenv(option, equal - option); + + if ((ix >= 0) && (*env != NULL)) { + /* String is already in the environment -- overwrite/remove it. + */ + if (remove) { + /* removing -- move all the later strings up */ + for ( ; env[ix] != NULL; ++ix) { + env[ix] = env[ix+1]; + } + + /* shrink the environment memory block + (ix now has number of strings, including NULL) -- + this realloc probably can't fail, since we're + shrinking a mem block, but we're careful anyway. */ + if (env = (char **) realloc(env, ix * sizeof(char *))) + _environ = env; + } + else { + /* replace the option */ + env[ix] = (char *) option; + } + } + else { + /* String is NOT in the environment */ + + if (!remove) { /* can't remove something that's not there */ + + /* Grow vector table by one */ + if (ix < 0) + ix = -ix; /* ix = length of environ table */ + + if (!(env = (char **)realloc(env, sizeof(char *) * (ix + 2)))) + goto unlock_error; + + env[ix] = (char *)option; + env[ix + 1] = NULL; + _environ = env; + } + } + +unlock_good: + _munlock( _ENV_LOCK ); + return(0); + +unlock_error: + _munlock( _ENV_LOCK ); + return -1; +} + + +/*** +*int findenv(name, len) - [STATIC] +* +*Purpose: +* Scan for the given string within the environment +* +*Entry: +* +*Exit: +* Returns the offset in "environ[]" of the given variable +* Returns the negative of the length of environ[] if not found. +* Returns 0 if the environment is empty. +* +* [NOTE: That a 0 return can mean that the environment is empty +* or that the string was found as the first entry in the array.] +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 findenv ( + const char *name, + int len + ) +{ + REG4 char **env = _environ; + REG2 const char *nm; + REG1 char *envname; + REG3 int l; + + + while (envname = *env) { + nm = name; + l = len; + while (l && *envname++ == *nm++) + l--; + + if (l == 0 && ( *envname == '=' || !*envname ) ) + return(env - _environ); + env++; + } + + return(-(env - _environ)); + +} + +#else /* _CRUISER_ */ + +#ifdef _WIN32_ + +/*** +*int _putenv(option) - add/replace/remove variable in environment +* +*Purpose: +* option should be of the form "option=value". If a string with the +* given option part already exists, it is replaced with the given +* string; otherwise the given string is added to the environment. +* If the string is of the form "option=", then the string is +* removed from the environment, if it exists. If the string has +* no equals sign, error is returned. +* +*Entry: +* char *option - option string to set in the environment list. +* should be of the form "option=value". +* +*Exit: +* returns 0 if OK, -1 if fails. +* +*Exceptions: +* +*Warning: +* This code will not work if variables are removed from the +* environment by deleting them from environ[]. Use _putenv("option=") +* to remove a variable. +* +*******************************************************************************/ + +#ifdef MTHREAD + +int _CALLTYPE1 _putenv ( + const char *option + ) +{ + int retval; + + _mlock(_ENV_LOCK); + + retval = _putenv_lk(option); + + _munlock(_ENV_LOCK); + + return retval; +} + +int _CALLTYPE1 _putenv_lk ( + const char *option + ) + +#else /* ndef MTHREAD */ + +int _CALLTYPE1 _putenv ( + const char *option + ) + +#endif /* MTHREAD */ + +{ + char **env; + const char *equal; + char *name, *value; + int ix; + int remove; /* 1 means remove string from environment */ + + /* check that the option string is valid and find the equal sign + */ + if ( (option == NULL) || ((equal = strchr(option, '=')) == NULL) ) + return(-1); + + /* check for the special case of '=' being the very first character + * of option. though the use of '=' in an environment variable name + * is documented as being illegal, the 'current directory' strings + * all look like this: + * + * =<Drive Letter>:=<Drive Letter><fully qualified path> + * + * handle this by setting the equal pointer to point to the second + * '=' if it exists. Otherwise, handle as before. + */ + if ( option == equal ) + if ( (equal = strchr(option + 1, '=')) == NULL ) + equal = option; + + /* if the character following '=' is null, we are removing the + * the environment variable. Otherwise, we are adding or updating + * an environment variable. + */ + remove = (*(equal + 1) == '\0'); + + /* see if _environ array exists */ + if (_environ == NULL) { + if ( remove ) + return 0; + else { + /* get an array and init it to NULL */ + if ( (_environ = malloc(sizeof(void *))) == NULL) + return -1; + *_environ = NULL; + } + } + + /* init env pointer */ + + env = _environ; + + /* See if the string is already in the environment */ + + ix = findenv(option, equal - option); + + if ((ix >= 0) && (*env != NULL)) { + /* String is already in the environment -- overwrite/remove it. + */ + if (remove) { + /* removing -- move all the later strings up */ + for ( ; env[ix] != NULL; ++ix) { + env[ix] = env[ix+1]; + } + + /* shrink the environment memory block + (ix now has number of strings, including NULL) -- + this realloc probably can't fail, since we're + shrinking a mem block, but we're careful anyway. */ + if (env = (char **) realloc(env, ix * sizeof(char *))) + _environ = env; + } + else { + /* replace the option */ + env[ix] = (char *) option; + } + } + else { + /* + * String is NOT in the environment + */ + if ( !remove ) { + + /* + * Append the string to the environ table. Note that + * table must be grown to do this. + */ + if (ix < 0) + ix = -ix; /* ix = length of environ table */ + + if ( (env = (char **)realloc(env, sizeof(char *) * + (ix + 2))) == NULL ) + return -1; + + env[ix] = (char *)option; + env[ix + 1] = NULL; + _environ = env; + } + else + /* + * We are asked to remove an environment var that + * isn't there...just return success + */ + return 0; + } + + /* + * Update the real environment. Don't give an error if this fails + * since the failure will not affect the user unless he/she is making + * direct API calls. + */ + if ( (name = malloc(strlen(option) + 2)) != NULL ) { + strcpy(name, option); + value = name + (equal - option); + *value++ = '\0'; + SetEnvironmentVariable(name, remove ? NULL : value); + free(name); + } + + return 0; +} + + +/*** +*int findenv(name, len) - [STATIC] +* +*Purpose: +* Scan for the given string within the environment +* +*Entry: +* +*Exit: +* Returns the offset in "environ[]" of the given variable +* Returns the negative of the length of environ[] if not found. +* Returns 0 if the environment is empty. +* +* [NOTE: That a 0 return can mean that the environment is empty +* or that the string was found as the first entry in the array.] +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 findenv ( + const char *name, + int len + ) +{ + char **env; + + for ( env = _environ ; *env != NULL ; env++ ) { + /* + * See if first len characters match, up to case + */ + if ( _strnicmp(name, *env, len) == 0 ) + /* + * the next character of the environment string must + * be an '=' or a '\0' + */ + if ( (*env)[len] == '=' || (*env)[len] == '\0' ) + return(env - _environ); +// +// We cannot break here since findenv must report the total number of strings. +// else +// break; + } + + return(-(env - _environ)); +} + + +#endif /* _WIN32_ */ +#endif /* _CRUISER_ */ + +#endif /* _POSIX_ */ diff --git a/private/crt32/misc/qsort.c b/private/crt32/misc/qsort.c new file mode 100644 index 000000000..30e15e6fd --- /dev/null +++ b/private/crt32/misc/qsort.c @@ -0,0 +1,329 @@ +/*** +*qsort.c - quicksort algorithm; qsort() library function for sorting arrays +* +* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* To implement the qsort() routine for sorting arrays. +* +*Revision History: +* 06-22-84 RN author +* 03-25-85 RN added pre-check for elements already in order to +* eliminate worst-case behavior. +* 05-18-86 TC changed to recurse on the smallest piece to avoid +* piece. unneccesary stack usage, and to iterate on +* largest +* 01-09-87 BCM fixed huge-array case where (num-1) * wid computation +* was overflowing (large/compact models only) +* 06-13-89 PHG made more efficient, many more comments, removed +* recursion +* 10-30-89 JCR Added _cdecl to prototypes +* 03-15-90 GJF Replaced _cdecl with _CALLTYPE1 and added #include +* <cruntime.h>. Also, fixed the copyright. +* 04-05-90 GJF Made shortsort() and swap() _CALLTYPE4. Also, added +* #include <search.h>. +* 10-04-90 GJF New-style function declarators. +* 12-28-90 SRW Added _CRUISER_ conditional around check_stack pragmas +* 01-24-91 SRW Added missing close comment in swap procedure +* 11-19-91 GJF Do the swap one character at a time to avoid alignment +* woes. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <search.h> + +/* prototypes for local routines */ +static void _CALLTYPE4 shortsort(char *lo, char *hi, unsigned width, + int (_CALLTYPE1 *comp)(const void *, const void *)); +static void _CALLTYPE4 swap(char *p, char *q, unsigned int width); + +/* this parameter defines the cutoff between using quick sort and + insertion sort for arrays; arrays with lengths shorter or equal to the + below value use insertion sort */ + +#define CUTOFF 8 /* testing shows that this is good value */ + + +/*** +*qsort(base, num, wid, comp) - quicksort function for sorting arrays +* +*Purpose: +* quicksort the array of elements +* side effects: sorts in place +* +*Entry: +* char *base = pointer to base of array +* unsigned num = number of elements in the array +* unsigned width = width in bytes of each array element +* int (*comp)() = pointer to function returning analog of strcmp for +* strings, but supplied by user for comparing the array elements. +* it accepts 2 pointers to elements and returns neg if 1<2, 0 if +* 1=2, pos if 1>2. +* +*Exit: +* returns void +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef _CRUISER_ +#pragma check_stack(on) /* lots of locals */ +#endif /* ndef _CRUISER_ */ + +/* sort the array between lo and hi (inclusive) */ + +void _CALLTYPE1 qsort ( + void *base, + unsigned num, + unsigned width, + int (_CALLTYPE1 *comp)(const void *, const void *) + ) +{ + char *lo, *hi; /* ends of sub-array currently sorting */ + char *mid; /* points to middle of subarray */ + char *loguy, *higuy; /* traveling pointers for partition step */ + unsigned size; /* size of the sub-array */ + char *lostk[30], *histk[30]; + int stkptr; /* stack for saving sub-array to be processed */ + + /* Note: the number of stack entries required is no more than + 1 + log2(size), so 30 is sufficient for any array */ + + if (num < 2 || width == 0) + return; /* nothing to do */ + + stkptr = 0; /* initialize stack */ + + lo = base; + hi = (char *)base + width * (num-1); /* initialize limits */ + + /* this entry point is for pseudo-recursion calling: setting + lo and hi and jumping to here is like recursion, but stkptr is + prserved, locals aren't, so we preserve stuff on the stack */ +recurse: + + size = (hi - lo) / width + 1; /* number of el's to sort */ + + /* below a certain size, it is faster to use a O(n^2) sorting method */ + if (size <= CUTOFF) { + shortsort(lo, hi, width, comp); + } + else { + /* First we pick a partititioning element. The efficiency of the + algorithm demands that we find one that is approximately the + median of the values, but also that we select one fast. Using + the first one produces bad performace if the array is already + sorted, so we use the middle one, which would require a very + wierdly arranged array for worst case performance. Testing shows + that a median-of-three algorithm does not, in general, increase + performance. */ + + mid = lo + (size / 2) * width; /* find middle element */ + swap(mid, lo, width); /* swap it to beginning of array */ + + /* We now wish to partition the array into three pieces, one + consisiting of elements <= partition element, one of elements + equal to the parition element, and one of element >= to it. This + is done below; comments indicate conditions established at every + step. */ + + loguy = lo; + higuy = hi + width; + + /* Note that higuy decreases and loguy increases on every iteration, + so loop must terminate. */ + for (;;) { + /* lo <= loguy < hi, lo < higuy <= hi + 1, + A[i] <= A[lo] for lo <= i <= loguy, + A[i] >= A[lo] for higuy <= i <= hi */ + + do { + loguy += width; + } while (loguy <= hi && comp(loguy, lo) <= 0); + + /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy, + either loguy > hi or A[loguy] > A[lo] */ + + do { + higuy -= width; + } while (higuy > lo && comp(higuy, lo) >= 0); + + /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi, + either higuy <= lo or A[higuy] < A[lo] */ + + if (higuy < loguy) + break; + + /* if loguy > hi or higuy <= lo, then we would have exited, so + A[loguy] > A[lo], A[higuy] < A[lo], + loguy < hi, highy > lo */ + + swap(loguy, higuy, width); + + /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top + of loop is re-established */ + } + + /* A[i] >= A[lo] for higuy < i <= hi, + A[i] <= A[lo] for lo <= i < loguy, + higuy < loguy, lo <= higuy <= hi + implying: + A[i] >= A[lo] for loguy <= i <= hi, + A[i] <= A[lo] for lo <= i <= higuy, + A[i] = A[lo] for higuy < i < loguy */ + + swap(lo, higuy, width); /* put partition element in place */ + + /* OK, now we have the following: + A[i] >= A[higuy] for loguy <= i <= hi, + A[i] <= A[higuy] for lo <= i < higuy + A[i] = A[lo] for higuy <= i < loguy */ + + /* We've finished the partition, now we want to sort the subarrays + [lo, higuy-1] and [loguy, hi]. + We do the smaller one first to minimize stack usage. + We only sort arrays of length 2 or more.*/ + + if ( higuy - 1 - lo >= hi - loguy ) { + if (lo + width < higuy) { + lostk[stkptr] = lo; + histk[stkptr] = higuy - width; + ++stkptr; + } /* save big recursion for later */ + + if (loguy < hi) { + lo = loguy; + goto recurse; /* do small recursion */ + } + } + else { + if (loguy < hi) { + lostk[stkptr] = loguy; + histk[stkptr] = hi; + ++stkptr; /* save big recursion for later */ + } + + if (lo + width < higuy) { + hi = higuy - width; + goto recurse; /* do small recursion */ + } + } + } + + /* We have sorted the array, except for any pending sorts on the stack. + Check if there are any, and do them. */ + + --stkptr; + if (stkptr >= 0) { + lo = lostk[stkptr]; + hi = histk[stkptr]; + goto recurse; /* pop subarray from stack */ + } + else + return; /* all subarrays done */ +} + +#ifdef _CRUISER_ +#pragma check_stack() /* revert to command line behaviour */ +#endif /* ndef _CRUISER_ */ + + +/*** +*shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays +* +*Purpose: +* sorts the sub-array of elements between lo and hi (inclusive) +* side effects: sorts in place +* assumes that lo < hi +* +*Entry: +* char *lo = pointer to low element to sort +* char *hi = pointer to high element to sort +* unsigned width = width in bytes of each array element +* int (*comp)() = pointer to function returning analog of strcmp for +* strings, but supplied by user for comparing the array elements. +* it accepts 2 pointers to elements and returns neg if 1<2, 0 if +* 1=2, pos if 1>2. +* +*Exit: +* returns void +* +*Exceptions: +* +*******************************************************************************/ + +static void _CALLTYPE4 shortsort ( + char *lo, + char *hi, + unsigned width, + int (_CALLTYPE1 *comp)(const void *, const void *) + ) +{ + char *p, *max; + + /* Note: in assertions below, i and j are alway inside original bound of + array to sort. */ + + while (hi > lo) { + /* A[i] <= A[j] for i <= j, j > hi */ + max = lo; + for (p = lo+width; p <= hi; p += width) { + /* A[i] <= A[max] for lo <= i < p */ + if (comp(p, max) > 0) { + max = p; + } + /* A[i] <= A[max] for lo <= i <= p */ + } + + /* A[i] <= A[max] for lo <= i <= hi */ + + swap(max, hi, width); + + /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */ + + hi -= width; + + /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */ + } + /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j, + so array is sorted */ +} + + +/*** +*swap(a, b, width) - swap two elements +* +*Purpose: +* swaps the two array elements of size width +* +*Entry: +* char *a, *b = pointer to two elements to swap +* unsigned width = width in bytes of each array element +* +*Exit: +* returns void +* +*Exceptions: +* +*******************************************************************************/ + +static void _CALLTYPE4 swap ( + char *a, + char *b, + unsigned width + ) +{ + char tmp; + + if ( a != b ) + /* Do the swap one character at a time to avoid potential alignment + problems. */ + while ( width-- ) { + tmp = *a; + *a++ = *b; + *b++ = tmp; + } +} diff --git a/private/crt32/misc/rand.c b/private/crt32/misc/rand.c new file mode 100644 index 000000000..b5df0798f --- /dev/null +++ b/private/crt32/misc/rand.c @@ -0,0 +1,133 @@ +/*** +*rand.c - random number generator +* +* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines rand(), srand() - random number generator +* +*Revision History: +* 03-16-84 RN initial version +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 05-31-88 PHG Merged DLL and normal versions +* 06-06-89 JCR 386 mthread support +* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 04-05-90 GJF Added #include <stdlib.h>. +* 10-04-90 GJF New-style function declarators. +* 07-17-91 GJF Multi-thread support for Win32 [_WIN32_]. +* 02-17-93 GJF Changed for new _getptd(). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <os2dll.h> +#include <stddef.h> +#include <stdlib.h> + +#ifndef MTHREAD +static long holdrand = 1L; +#endif + +/*** +*void srand(seed) - seed the random number generator +* +*Purpose: +* Seeds the random number generator with the int given. Adapted from the +* BASIC random number generator. +* +*Entry: +* unsigned seed - seed to seed rand # generator with +* +*Exit: +* None. +* +*Exceptions: +* +*******************************************************************************/ + +void _CRTAPI1 srand ( + unsigned int seed + ) +{ +#ifdef MTHREAD + +#ifdef _CRUISER_ + + struct _tiddata * tdata; + + tdata = _gettidtab(); /* get tid's data address */ + tdata->_holdrand = (long)seed; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + _getptd()->_holdrand = (unsigned long)seed; + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + +#else + holdrand = (long)seed; +#endif +} + + +/*** +*int rand() - returns a random number +* +*Purpose: +* returns a pseudo-random number 0 through 32767. +* +*Entry: +* None. +* +*Exit: +* Returns a pseudo-random number 0 through 32767. +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI1 rand ( + void + ) +{ +#ifdef MTHREAD + +#ifdef _CRUISER_ + + struct _tiddata * tdata; + + tdata = _gettidtab(); /* get tid's data address */ + return(((tdata->_holdrand = tdata->_holdrand * 214013L + 2531011L) >> + 16) & 0x7fff); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + _ptiddata ptd = _getptd(); + + return( ((ptd->_holdrand = ptd->_holdrand * 214013L + + 2531011L) >> 16) & 0x7fff ); + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + +#else + return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff); +#endif +} diff --git a/private/crt32/misc/rotl.c b/private/crt32/misc/rotl.c new file mode 100644 index 000000000..79af5779f --- /dev/null +++ b/private/crt32/misc/rotl.c @@ -0,0 +1,90 @@ +/*** +*rotl.c - rotate an unsigned integer left +* +* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _rotl() - performs a rotate left on an unsigned integer. +* +*Revision History: +* 06-02-89 PHG Module created +* 11-03-89 JCR Added _lrotl +* 03-15-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 10-04-90 GJF New-style function declarators. +* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too. +* 09-02-92 GJF Don't build for POSIX. +* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <stdlib.h> +#include <limits.h> + +#ifdef _MSC_VER +#pragma function(_lrotl,_rotl) +#endif + +#if UINT_MAX != 0xffffffff +#error This module assumes 32-bit integers +#endif + +#if (UINT_MAX != ULONG_MAX) +#error This module assumes sizeof(int) == sizeof(long) +#endif + +/*** +*unsigned _rotl(val, shift) - int rotate left +* +*Purpose: +* Performs a rotate left on an unsigned integer. +* +* [Note: The _lrotl entry is based on the assumption +* that sizeof(int) == sizeof(long).] +*Entry: +* unsigned val: value to rotate +* int shift: number of bits to shift by +* +*Exit: +* returns rotated value +* +*Exceptions: +* None. +* +*******************************************************************************/ + +unsigned long _CALLTYPE1 _lrotl ( + unsigned long val, + int shift + ) +{ + return( (unsigned long) _rotl((unsigned) val, shift) ); +} + +unsigned _CALLTYPE1 _rotl ( + unsigned val, + int shift + ) +{ + register unsigned hibit; /* non-zero means hi bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while (shift--) { + hibit = num & 0x80000000; /* get high bit */ + num <<= 1; /* shift left one bit */ + if (hibit) + num |= 1; /* set lo bit if hi bit was set */ + } + + return num; +} + + +#endif diff --git a/private/crt32/misc/rotr.c b/private/crt32/misc/rotr.c new file mode 100644 index 000000000..5abe91f23 --- /dev/null +++ b/private/crt32/misc/rotr.c @@ -0,0 +1,90 @@ +/*** +*rotr.c - rotate an unsigned integer right +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _rotr() - performs a rotate right on an unsigned integer. +* +*Revision History: +* 06-02-89 PHG Module created +* 11-03-89 JCR Added _lrotl +* 03-15-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 10-04-90 GJF New-style function declarators. +* 04-01-91 SRW Enable #pragma function for i386 _WIN32_ builds too. +* 09-02-92 GJF Don't build for POSIX. +* 03-09-94 RDL Enable #pragma function for i386 _WIN32_ builds too. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <stdlib.h> +#include <limits.h> + +#ifdef _MSC_VER +#pragma function(_lrotr,_rotr) +#endif + +#if UINT_MAX != 0xffffffff +#error This module assumes 32-bit integers +#endif + +#if (UINT_MAX != ULONG_MAX) +#error This module assumes sizeof(int) == sizeof(long) +#endif + +/*** +*unsigned _rotr(val, shift) - int rotate right +* +*Purpose: +* Performs a rotate right on an unsigned integer. +* +* [Note: The _lrotl entry is based on the assumption +* that sizeof(int) == sizeof(long).] +*Entry: +* unsigned val: value to rotate +* int shift: number of bits to shift by +* +*Exit: +* returns rotated values +* +*Exceptions: +* None. +* +*******************************************************************************/ + +unsigned long _CALLTYPE1 _lrotr ( + unsigned long val, + int shift + ) +{ + return( (unsigned long) _rotr((unsigned) val, shift) ); +} + +unsigned _CALLTYPE1 _rotr ( + unsigned val, + int shift + ) +{ + register unsigned lobit; /* non-zero means lo bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while (shift--) { + lobit = num & 1; /* get high bit */ + num >>= 1; /* shift right one bit */ + if (lobit) + num |= 0x80000000; /* set hi bit if lo bit was set */ + } + + return num; +} + + +#endif diff --git a/private/crt32/misc/searchen.c b/private/crt32/misc/searchen.c new file mode 100644 index 000000000..8b92e476f --- /dev/null +++ b/private/crt32/misc/searchen.c @@ -0,0 +1,114 @@ +/*** +*searchenv.c - find a file using paths from an environment variable +* +* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* to search a set a directories specified by an environment variable +* for a specified file name. If found the full path name is returned. +* +*Revision History: +* 06-15-87 DFW initial implementation +* 08-06-87 JCR Changed directory delimeter from '/' to '\'. +* 09-24-87 JCR Removed 'const' from declarations (caused cl warnings). +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 02-17-88 JCR Added 'const' copy_path local to get rid of cl warning. +* 07-19-88 SKS Fixed bug if root directory is current directory +* 08-03-89 JCR Allow quoted strings in file/path names +* 08-29-89 GJF Changed copy_path() to _getpath() and moved it to it's +* own source file. Also fixed handling of multiple semi- +* colons. +* 11-20-89 GJF Added const attribute to types of fname and env_var. +* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include +* <cruntime.h>. Also, cleaned up the formatting a bit. +* 07-25-90 SBM Removed redundant include (stdio.h) +* 10-04-90 GJF New-style function declarator. +* 01-22-91 GJF ANSI naming. +* 08-26-92 GJF Include unistd.h for POSIX build. +* +*******************************************************************************/ + +#include <cruntime.h> +#ifdef _POSIX_ +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <direct.h> +#include <io.h> +#include <internal.h> + +/*** +*_searchenv() - search for file along paths from environment variable +* +*Purpose: +* to search for a specified file in the directory(ies) specified by +* a given environment variable, and, if found, to return the full +* path name of the file. The file is first looked for in the current +* working directory, prior to looking in the paths specified by env_var. +* +*Entry: +* fname - name of file to search for +* env_var - name of environment variable to use for paths +* path - pointer to storage for the constructed path name +* +*Exit: +* path - pointer to constructed path name, if the file is found, otherwise +* it points to the empty string. +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _searchenv ( + const char *fname, + const char *env_var, + register char *path + ) +{ + register char *p; + register int c; + char *env_p; + +#ifdef _POSIX_ + if (access(fname, 0) == 0) { +#else + if (_access(fname, 0) == 0) { +#endif + /* exists in this directory - get cwd and concatenate file + name */ + _getcwd(path, _MAX_PATH); + if(path[3]) /* Do NOT add `\' to root directory */ + strcat(path, "\\"); + strcat(path, fname); + return; + } + if ((env_p = getenv(env_var)) == NULL) { + /* no such environment var. and not in cwd, so return empty + string */ + *path = '\0'; + return; + } + while ( (env_p = _getpath(env_p, path, 0)) && *path ) { + /* path now holds nonempty pathname from env_p, concatenate + the file name and go */ + p = path + strlen(path); + if (((c = *(p - 1)) != '/') && (c != '\\') && (c != ':')) { + /* add a trailing '\' */ + *p++ = '\\'; + } + /* p now points to character following trailing '/', '\' + or ':' */ + strcpy(p, fname); +#ifdef _POSIX_ + if (access(path, 0) == 0) { +#else + if (_access(path, 0) == 0) { +#endif + /* found a match, we're done */ + return; + } + } + /* if we get here, we never found it, return empty string */ + *path = '\0'; +} diff --git a/private/crt32/misc/setlocal.c b/private/crt32/misc/setlocal.c new file mode 100644 index 000000000..4fa3bbc05 --- /dev/null +++ b/private/crt32/misc/setlocal.c @@ -0,0 +1,620 @@ +/*** +*setlocal.c - Contains the setlocale function +* +* Copyright (c) 1988-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Contains the setlocale() function. +* +*Revision History: +* 03-21-89 JCR Module created. +* 09-25-89 GJF Fixed copyright. Checked for compatibility with Win 3.0 +* 09-25-90 KRS Major rewrite--support more than "C" locale if _INTL. +* 11-05-91 ETC Get 09-25-90 working for C and "" locales; separate +* setlocal.h; add Init functions. +* 12-05-91 ETC Separate nlsdata.c; add mt support; remove calls to +* itself. +* 12-20-91 ETC Added _getlocaleinfo api interface function. +* 09-25-92 KRS Fix for latest NLSAPI changes, etc. +* 01-25-93 KRS Fix for latest changes, clean up code, etc. +* 02-02-93 CFW Many modifications and bug fixes (all under _INTL). +* 02-08-93 CFW Bug fixes and casts to avoid warnings (all under _INTL). +* 02-17-93 CFW Removed re-call of init() functions in case of failure. +* 03-01-93 CFW Check GetQualifiedLocale return value. +* 03-02-93 CFW Added POSIX conformance, check environment variables. +* 03-09-93 CFW Set CP to CP_ACP when changing to C locale. +* 03-17-93 CFW Change expand to expandlocale, prepend _ to internal functions, +* lots of POSIX fixup. +* 03-23-93 CFW Add _ to GetQualifiedLocale call. +* 03-24-93 CFW Change to _get_qualified_locale, support ".codepage". +* 05-10-93 CFW Disallow setlocale(LC_*, "."). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <locale.h> +#ifdef _INTL +#include <os2dll.h> +#include <malloc.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> /* for strtol */ +#include <setlocal.h> + +#ifdef MTHREAD +/* + * Check order of locale category multithread locks. + * (needed by _setlocale_set_cat) + */ +#if _LC_COLLATE_LOCK != _SETLOCALE_LOCK + LC_COLLATE || \ + _LC_CTYPE_LOCK != _SETLOCALE_LOCK + LC_CTYPE || \ + _LC_MONETARY_LOCK != _SETLOCALE_LOCK + LC_MONETARY || \ + _LC_NUMERIC_LOCK != _SETLOCALE_LOCK + LC_NUMERIC || \ + _LC_TIME_LOCK != _SETLOCALE_LOCK + LC_TIME + +#error Locale category multithread locks are disordered +#endif +#endif /* MTHREAD */ + +#endif /* _INTL */ + +/* C locale */ +static char _clocalestr[] = "C"; +#ifdef _POSIX_ +static char _posixlocalestr[] = "POSIX"; +#endif + + +#ifdef _INTL +/* CONSIDER: for granularity, reference from approp component (lconv.c, etc.) */ +int _CRTAPI3 _init_collate(void); +int _CRTAPI3 _init_ctype(void); +int _CRTAPI3 _init_monetary(void); +int _CRTAPI3 _init_numeric(void); +int _CRTAPI3 _init_time(void); +int _CRTAPI3 _init_dummy(void); + +static struct { + const char * catname; + char * locale; + int (* init)(void); +} _lc_category[LC_MAX-LC_MIN+1] = { + /* code assumes locale initialization is "_clocalestr" */ + { "LC_ALL", NULL, _init_dummy /* never called */ }, + { "LC_COLLATE", _clocalestr, _init_collate }, + { "LC_CTYPE", _clocalestr, _init_ctype }, + { "LC_MONETARY", _clocalestr, _init_monetary }, + { "LC_NUMERIC", _clocalestr, _init_numeric }, + { "LC_TIME", _clocalestr, _init_time } +}; +/* CONSIDER: _init_* functions should map to _init_dummy when not linked in */ + +/* helper function prototypes */ +char * _expandlocale(char *, char *, LC_ID *, UINT *, int); +void _strcats(char *, int, ...); +void _lc_lctostr(char *, const LC_STRINGS *); +int _lc_strtolc(LC_STRINGS *, const char *); +static char * _CRTAPI3 _setlocale_set_cat(int, const char *); +static char * _CRTAPI3 _setlocale_get_all(void); +#endif /* _INTL */ + +/*** +*char * setlocale(int category, char *locale) - Set one or all locale categories +* +*Purpose: +* The setlocale() routine allows the user to set one or more of +* the locale categories to the specific locale selected by the +* user. [ANSI] +* +* NOTE: Under !_INTL, the C libraries only support the "C" locale. +* Attempts to change the locale will fail. +* +*Entry: +* int category = One of the locale categories defined in locale.h +* char *locale = String identifying a specific locale or NULL to +* query the current locale. +* +*Exit: +* If supplied locale pointer == NULL: +* +* Return pointer to current locale string and do NOT change +* the current locale. +* +* If supplied locale pointer != NULL: +* +* If locale string is '\0', set locale to default. +* +* If desired setting can be honored, return a pointer to the +* locale string for the appropriate category. +* +* If desired setting can NOT be honored, return NULL. +* +*Exceptions: +* Compound locale strings of the form "LC_COLLATE=xxx;LC_CTYPE=xxx;..." +* are allowed for the LC_ALL category. This is to support the ability +* to restore locales with the returned string, as specified by ANSI. +* Setting the locale with a compound locale string will succeed unless +* *all* categories failed. The returned string will reflect the current +* locale. For example, if LC_CTYPE fails in the above string, setlocale +* will return "LC_COLLATE=xxx;LC_CTYPE=yyy;..." where yyy is the +* previous locale (or the C locale if restoring the previous locale +* also failed). Unrecognized LC_* categories are ignored. +* +*******************************************************************************/ +char * _CRTAPI1 setlocale ( + int _category, + const char *_locale + ) +{ +#ifdef _INTL +char * retval; +#endif + + /* Validate category */ + if ((_category < LC_MIN) || (_category > LC_MAX)) + return NULL; + + /* Interpret locale */ + +#ifndef _INTL /* trivial ANSI support */ + if ( (_locale == NULL) || + (_locale[0] == '\0') || + ( (_locale[0]=='C') && (_locale[1]=='\0')) +#ifdef _POSIX_ + || (!strcmp(_locale,"POSIX")) +#endif + ) +#ifdef _POSIX_ + return _posixlocalestr; +#else + return _clocalestr; +#endif + else + return NULL; + +#else /* _INTL */ + +_mlock (_SETLOCALE_LOCK); + + if (_category != LC_ALL) + { + retval = (_locale) ? _setlocale_set_cat(_category,_locale) : + _lc_category[_category].locale; + + } else { /* LC_ALL */ + + char lctemp[MAX_LC_LEN]; + int i; + int same = 1; + int fLocaleSet = 0; /* flag to indicate if anything successfully set */ + + if (_locale != NULL) + { + if ( (_locale[0]=='L') && (_locale[1]=='C') && (_locale[2]=='_') ) + { + /* parse compound locale string */ + size_t len; + const char * p = _locale; /* start of string to parse */ + const char * s; + + do { + s = strpbrk(p,"=;"); + if ((s==(char *)NULL) || (!(len=s-p)) || (*s==';')) + { + _munlock (_SETLOCALE_LOCK); + return NULL; /* syntax error */ + } + + /* match with known LC_ strings, if possible, else ignore */ + for (i=LC_ALL+1; i<=LC_MAX; i++) + { + if ((!strncmp(_lc_category[i].catname,p,len)) + && (len==strlen(_lc_category[i].catname))) + { + break; /* matched i */ + } + } /* no match if (i>LC_MAX) -- just ignore */ + + if ((!(len = strcspn(++s,";"))) && (*s!=';')) + { + _munlock (_SETLOCALE_LOCK); + return NULL; /* syntax error */ + } + + if (i<=LC_MAX) + { + /* CONSIDER: check for repeated categories? */ + strncpy(lctemp, s, len); + lctemp[len]='\0'; /* null terminate string */ + + /* don't fail unless all categories fail */ + if (_setlocale_set_cat(i,lctemp)) + fLocaleSet++; /* record a success */ + } + if (*(p = s+len)!='\0') + p++; /* skip ';', if present */ + + } while (*p); + + retval = (fLocaleSet) ? _setlocale_get_all() : NULL; + + /* CONSIDER: LC_CTYPE should be done first. _init_monetary for example + will convert wide strings to multibyte (dependent on ctype). + This is currently not a problem; ctype is done second; collate is done + first, but it does not require ctype. */ + /* Not necessarily true when a compound locale string is used, but WE always + put it in the right order. */ + + } else { /* simple LC_ALL locale string */ + + /* confirm locale is supported, get expanded locale */ + if (retval = _expandlocale((char *)_locale, lctemp, NULL, NULL, _category)) + { + for (i=LC_MIN; i<=LC_MAX; i++) + { + if (i!=LC_ALL) + { + if (strcmp(lctemp, _lc_category[i].locale)) + { + if (_setlocale_set_cat(i, lctemp)) + { + fLocaleSet++; /* record a success */ + } + else + { + same = 0; /* record a failure */ + } + } + else + fLocaleSet++; /* trivial succcess */ + } + } +#ifdef _POSIX_ + /* special case for POSIX - since LC_ALL expands, + one LC_ALL call may set many different categories, + must assume not same, get full string */ + same = 0; +#endif + if (same) /* needn't call setlocale_get_all() if all the same */ + { + retval = _setlocale_get_all(); + /* retval set above */ + free(_lc_category[LC_ALL].locale); + _lc_category[LC_ALL].locale = NULL; + } + else + retval = (fLocaleSet) ? _setlocale_get_all() : NULL; + } + } + } else { /* LC_ALL & NULL */ + retval = _setlocale_get_all (); + } + } + + /* common exit point */ + _munlock (_SETLOCALE_LOCK); + return retval; + +#endif /* _INTL */ + +} /* setlocale */ + + +#ifdef _INTL /* rest are international helpers */ +static char * _CRTAPI3 _setlocale_set_cat ( + int category, + const char * locale + ) +{ + char * oldlocale; + LCID oldhandle; + UINT oldcodepage; + LC_ID oldid; + + LC_ID idtemp; + UINT cptemp; + char lctemp[MAX_LC_LEN]; + char * pch; + + /* lock this category to keep other library functions */ + /* from using locale handles, information, etc. */ + + _mlock (_SETLOCALE_LOCK + category); + + if (!_expandlocale((char *)locale, lctemp, &idtemp, &cptemp, category)) + { + _munlock (_SETLOCALE_LOCK + category); + return NULL; /* unrecognized locale */ + } + + if (!(pch = (char *)malloc(strlen(lctemp)+1))) + { + _munlock (_SETLOCALE_LOCK + category); + return NULL; /* error if malloc fails */ + } + + oldlocale = _lc_category[category].locale; /* save for possible restore*/ + oldhandle = _lc_handle[category]; + memcpy((void *)&oldid, (void *)&_lc_id[category], sizeof(oldid)); + oldcodepage = _lc_codepage; + + /* update locale string */ + _lc_category[category].locale = strcpy(pch,lctemp); + _lc_handle[category] = MAKELCID(idtemp.wLanguage, SORT_DEFAULT); + memcpy((void *)&_lc_id[category], (void *)&idtemp, sizeof(idtemp)); + + if (category==LC_CTYPE) + _lc_codepage = cptemp; + + if (_lc_category[category].init()) + { + /* restore previous state! */ + _lc_category[category].locale = oldlocale; + free(pch); + _lc_handle[category] = oldhandle; + _lc_codepage = oldcodepage; + + _munlock (_SETLOCALE_LOCK + category); + return NULL; /* error if non-zero return */ + } + + /* locale set up successfully */ + /* Cleanup */ + if ((oldlocale != _clocalestr) +#ifdef _POSIX_ + && (oldlocale!=_posixlocalestr) +#endif + ) + free(oldlocale); + + _munlock (_SETLOCALE_LOCK + category); + + return _lc_category[category].locale; + +} /* _setlocale_set_cat */ + + + +static char * _CRTAPI3 _setlocale_get_all ( + void + ) +{ + int i; + int same = 1; + /* allocate memory if necessary */ + if (!_lc_category[LC_ALL].locale) + _lc_category[LC_ALL].locale = malloc((MAX_LC_LEN+1) * (LC_MAX-LC_MIN+1) + CATNAMES_LEN); + + _lc_category[LC_ALL].locale[0] = '\0'; + for (i=LC_MIN+1; ; i++) + { + _strcats(_lc_category[LC_ALL].locale, 3, _lc_category[i].catname,"=",_lc_category[i].locale); + if (i<LC_MAX) + { + strcat(_lc_category[LC_ALL].locale,";"); + if (strcmp(_lc_category[i].locale, _lc_category[i+1].locale)) + same=0; + } + else + { + if (!same) + return _lc_category[LC_ALL].locale; + else + { + free(_lc_category[LC_ALL].locale); /* free */ + _lc_category[LC_ALL].locale = (char *)NULL; + return _lc_category[LC_CTYPE].locale; + } + } + } +} /* _setlocale_get_all */ + + +char * _expandlocale ( + char *expr, + char * output, + LC_ID * id, + UINT * cp, + int category + ) +{ + static LC_ID cacheid = {0, 0, 0}; + static UINT cachecp = 0; + static char cachein[MAX_LC_LEN] = "C"; + static char cacheout[MAX_LC_LEN] = "C"; + + if (!expr) + return NULL; /* error if no input */ + +#ifdef _POSIX_ + if (!*expr) + { + /* POSIX: when locale=="", look first at the environment variables: + 1) use LC_ALL EV if defined and not null (LC_ALL expands to LC_*) + 2) use EV that matches category and is not null + 3) use LANG EV if defined and not null + otherwise, we fall through to get system default */ + + char *envar; + + if (category == LC_ALL && (envar = getenv("LC_ALL"))) + { + if (!*envar) + { + /* LC_ALL expands to LC_*, set output to "", each category will be + expanded individually */ + *output = '\0'; + return output; + } + else { + expr = envar; + } + } + else { + if ((envar = getenv(_lc_category[category].catname)) && *envar || + (envar = getenv("LANG")) && *envar) + { + expr = envar; + } + } + } +#endif /* _POSIX_ */ + + if (((*expr=='C') && (!expr[1])) +#ifdef _POSIX_ + || (!strcmp(expr, _posixlocalestr)) +#endif + ) /* for "C" locale, just return */ + { +#ifdef _POSIX_ + strcpy(output, _posixlocalestr); +#else + *output = 'C'; + output[1] = '\0'; +#endif + if (id) + { + id->wLanguage = 0; + id->wCountry = 0; + id->wCodePage = 0; + } + if (cp) + { + *cp = CP_ACP; /* return to ANSI code page */ + } + return output; /* "C" */ + } + + /* first, make sure we didn't just do this one */ + if (strcmp(cacheout,expr) && strcmp(cachein,expr)) + { + /* do some real work */ + const LC_STRINGS names; + + if (_lc_strtolc((LC_STRINGS *)&names, (const char *)expr)) + return NULL; /* syntax error */ + + if (!_get_qualified_locale((const DWORD)QF_STRINGS, (const LPVOID)&names, + (LPLC_ID)&cacheid, (LPLC_STRINGS)&names)) + return NULL; /* locale not recognized/supported */ + + /* begin: cache atomic section */ + + cachecp = cacheid.wCodePage; + + _lc_lctostr((char *)cacheout, &names); + + /* Don't cache "" empty string */ + if (*expr) + strcpy(cachein, expr); + else + strcpy(cachein, cacheout); + + /* end: cache atomic section */ + } + if (id) + memcpy((void *)id, (void *)&cacheid, sizeof(cacheid)); /* possibly return LC_ID */ + if (cp) + memcpy((void *)cp, (void *)&cachecp, sizeof(cachecp)); /* possibly return cp */ + + strcpy(output,cacheout); + return cacheout; /* return fully expanded locale string */ +} + +/* helpers */ + +int _CRTAPI3 _init_dummy(void) /* default routine for locale initializer */ +{ + return 0; +} + +void _strcats + ( + char *outstr, + int n, + ... + ) +{ + int i; + va_list substr; + + va_start (substr, n); + + for (i =0; i<n; i++) + { + strcat(outstr, va_arg(substr, char *)); + } + va_end(substr); +} + +int _lc_strtolc + ( + LC_STRINGS *names, + const char *locale + ) +{ + int i, len; + char ch; + + memset((void *)names, '\0', sizeof(LC_STRINGS)); /* clear out result */ + + if (*locale=='\0') + return 0; /* trivial case */ + + // only code page is given + if (locale[0] == '.' && locale[1] != '\0') + { + strcpy((char *)names->szCodePage, &locale[1]); + return 0; + } + + for (i=0; ; i++) + { + if (!(len=strcspn(locale,"_.,"))) + return -1; /* syntax error */ + + ch = locale[len]; + + if ((i==0) && (len<MAX_LANG_LEN) && (ch!='.')) + strncpy((char *)names->szLanguage, locale, len); + + else if ((i==1) && (len<MAX_CTRY_LEN) && (ch!='_')) + strncpy((char *)names->szCountry, locale, len); + + else if ((i==2) && (ch=='\0' || ch==',')) + strncpy((char *)names->szCodePage, locale, len); + + else + return -1; /* error parsing locale string */ + + if (ch==',') + { + /* modifier not used in current implementation, but it + must be parsed to for POSIX/XOpen conformance */ + /* strncpy(names->szModifier, locale, MAX_MODIFIER_LEN-1); */ + break; + } + + if (!ch) + break; + locale+=(len+1); + } + return 0; +} + +void _lc_lctostr + ( + char *locale, + const LC_STRINGS *names + ) +{ + strcpy(locale, (char *)names->szLanguage); + if (*(names->szCountry)) + _strcats(locale, 2, "_", names->szCountry); + if (*(names->szCodePage)) + _strcats(locale, 2, ".", names->szCodePage); + /* if (names->szModifier) + _strcats(locale, 2, ",", names->szModifier); */ +} + +#endif /* _INTL */ diff --git a/private/crt32/misc/setmbval.c b/private/crt32/misc/setmbval.c new file mode 100644 index 000000000..bbbf48f3f --- /dev/null +++ b/private/crt32/misc/setmbval.c @@ -0,0 +1,35 @@ +/*** +*setmbval.c - sets __invalid_mb_chars variable +* +* Copyright (c) 1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* sets __invalid_mb_chars flag to value apppropriate to the NLS API +* call support. Older versions of NT do not support this flag. +* +** +*Revision History: +* 10-22-93 CFW Module created. +* +*******************************************************************************/ + +#include <windows.h> +#include <internal.h> + + +void __set_invalid_mb_chars(void) +{ + char *astring = "a"; /* test string */ + + /* + * Determine whether API supports this flag by making a dummy call. + * + */ + + if (0 != MultiByteToWideChar(0, MB_ERR_INVALID_CHARS, astring, -1, NULL, 0)) + __invalid_mb_chars = MB_ERR_INVALID_CHARS; + else + __invalid_mb_chars = 0; +} + + diff --git a/private/crt32/misc/sources b/private/crt32/misc/sources new file mode 100644 index 000000000..cd3f28bea --- /dev/null +++ b/private/crt32/misc/sources @@ -0,0 +1,129 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + jeffrob 29-sep-1990, use crt32.def + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=crt +MINORCOMP=misc + +TARGETNAME=misc +TARGETPATH=..\obj +TARGETTYPE=LIBRARY +386_STDCALL=0 + +!INCLUDE ..\crt32.def + +SOURCES=abort.c \ + abs.c \ + assert.c \ + bsearch.c \ + cmiscdat.c \ + ctype.c \ + div.c \ + ldiv.c \ + getenv.c \ + getpath.c \ + getqloc.c \ + initcoll.c \ + initctyp.c \ + inithelp.c \ + initmon.c \ + initnum.c \ + inittime.c \ + labs.c \ + lconv.c \ + lfind.c \ + lsearch.c \ + makepath.c \ + mbval.c \ + onexit.c \ + nlsdata1.c \ + nlsdata2.c \ + nlsdata3.c \ + perror.c \ + purevirt.c \ + putenv.c \ + qsort.c \ + rand.c \ + rotl.c \ + rotr.c \ + searchen.c \ + setlocal.c \ + setmbval.c \ + splitpat.c \ + _strerr.c \ + strerror.c \ + syserr.c \ + umask.c \ + winsig.c \ + winxfltr.c \ + wrt2err.c + +i386_SOURCES=i386\setjmpex.asm \ + i386\setjmp.asm \ + i386\setjmp3.asm \ + i386\longjmp.asm \ + i386\sehsupp.c \ + i386\exsup.asm \ + i386\exsup2.asm \ + i386\exsup3.asm + +MIPS_SOURCES=mips\chandler.c \ + mips\setjmp.s \ + mips\setjmpex.s \ + mips\longjmp.s \ + mips\jmpuwind.s + +ALPHA_SOURCES=alpha\chandler.c \ + alpha\divdat.s \ + alpha\divide2.s \ + alpha\extv.s \ + alpha\extvvol.s \ + alpha\extzv.s \ + alpha\extzvvol.s \ + alpha\ghandler.c \ + alpha\insv.s \ + alpha\insvvol.s \ + alpha\jmpuwind.s \ + alpha\longjmp.s \ + alpha\otsdiv.s \ + alpha\otsjmp.s \ + alpha\otsjmpex.s \ + alpha\otsuwind.s \ + alpha\scmpeql.s \ + alpha\scmpeqlp.s \ + alpha\scmpleq.s \ + alpha\scmpleqp.s \ + alpha\scmplss.s \ + alpha\scmplssp.s \ + alpha\setjmp.s \ + alpha\setjmpex.s \ + alpha\sfill.s \ + alpha\sloc.s \ + alpha\smove.s \ + alpha\smovem.s \ + alpha\strans.s \ + alpha\strcmp_.s \ + alpha\strcpy_.s \ + alpha\strlen_.s \ + alpha\szero.s diff --git a/private/crt32/misc/splitpat.c b/private/crt32/misc/splitpat.c new file mode 100644 index 000000000..f85b26b1e --- /dev/null +++ b/private/crt32/misc/splitpat.c @@ -0,0 +1,201 @@ +/*** +*splitpath.c - break down path name into components +* +* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* To provide support for accessing the individual components of an +* arbitrary path name +* +*Revision History: +* 06-14-87 DFW initial implementation +* 09-23-87 JCR Removed 'const' from declarations (fixed cl warnings) +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 11-20-89 GJF Fixed indents, copyright. Added const attribute to +* type of path. +* 03-15-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include +* <cruntime.h>. +* 07-25-90 SBM Removed redundant include (stdio.h), replaced local +* MIN macro with standard min macro +* 10-04-90 GJF New-style function declarator. +* 01-22-91 GJF ANSI naming. +* 11-20-92 KRS Port _MBCS support from 16-bit tree. +* 05-12-93 KRS Add fix for MBCS max path handling. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> +#include <string.h> +#ifdef _MBCS +#include <mbstring.h> +#include <mbctype.h> +#include <mbdata.h> +#endif + +#ifdef _MBCS +#define STRNCPY _mbsnbcpy +#else +#define STRNCPY strncpy +#endif + +/*** +*_splitpath() - split a path name into its individual components +* +*Purpose: +* to split a path name into its individual components +* +*Entry: +* path - pointer to path name to be parsed +* drive - pointer to buffer for drive component, if any +* dir - pointer to buffer for subdirectory component, if any +* fname - pointer to buffer for file base name component, if any +* ext - pointer to buffer for file name extension component, if any +* +*Exit: +* drive - pointer to drive string. Includes ':' if a drive was given. +* dir - pointer to subdirectory string. Includes leading and trailing +* '/' or '\', if any. +* fname - pointer to file base name +* ext - pointer to file extension, if any. Includes leading '.'. +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _splitpath ( + register const char *path, + char *drive, + char *dir, + char *fname, + char *ext + ) +{ + register char *p; + char *last_slash = NULL, *dot = NULL; + unsigned len; + + /* we assume that the path argument has the following form, where any + * or all of the components may be missing. + * + * <drive><dir><fname><ext> + * + * and each of the components has the following expected form(s) + * + * drive: + * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a + * ':' + * dir: + * 0 to _MAX_DIR-1 characters in the form of an absolute path + * (leading '/' or '\') or relative path, the last of which, if + * any, must be a '/' or '\'. E.g - + * absolute path: + * \top\next\last\ ; or + * /top/next/last/ + * relative path: + * top\next\last\ ; or + * top/next/last/ + * Mixed use of '/' and '\' within a path is also tolerated + * fname: + * 0 to _MAX_FNAME-1 characters not including the '.' character + * ext: + * 0 to _MAX_EXT-1 characters where, if any, the first must be a + * '.' + * + */ + + /* extract drive letter and :, if any */ + + if (*(path + _MAX_DRIVE - 2) == ':') { + if (drive) { + strncpy(drive, path, _MAX_DRIVE - 1); + *(drive + _MAX_DRIVE-1) = '\0'; + } + path += _MAX_DRIVE - 1; + } + else if (drive) { + *drive = '\0'; + } + + /* extract path string, if any. Path now points to the first character + * of the path, if any, or the filename or extension, if no path was + * specified. Scan ahead for the last occurence, if any, of a '/' or + * '\' path separator character. If none is found, there is no path. + * We will also note the last '.' character found, if any, to aid in + * handling the extension. + */ + + for (last_slash = NULL, p = (char *)path; *p; p++) { +#ifdef _MBCS + if (_ISLEADBYTE (*p)) + p++; + else { +#endif + if (*p == '/' || *p == '\\') + /* point to one beyond for later copy */ + last_slash = p + 1; + else if (*p == '.') + dot = p; +#ifdef _MBCS + } +#endif + } + + if (last_slash) { + + /* found a path - copy up through last_slash or max. characters + * allowed, whichever is smaller + */ + + if (dir) { + len = __min((last_slash - path), (_MAX_DIR - 1)); + STRNCPY(dir, path, len); + *(dir + len) = '\0'; + } + path = last_slash; + } + else if (dir) { + + /* no path found */ + + *dir = '\0'; + } + + /* extract file name and extension, if any. Path now points to the + * first character of the file name, if any, or the extension if no + * file name was given. Dot points to the '.' beginning the extension, + * if any. + */ + + if (dot && (dot >= path)) { + /* found the marker for an extension - copy the file name up to + * the '.'. + */ + if (fname) { + len = __min((dot - path), (_MAX_FNAME - 1)); + STRNCPY(fname, path, len); + *(fname + len) = '\0'; + } + /* now we can get the extension - remember that p still points + * to the terminating nul character of path. + */ + if (ext) { + len = __min((p - dot), (_MAX_EXT - 1)); + STRNCPY(ext, dot, len); + *(ext + len) = '\0'; + } + } + else { + /* found no extension, give empty extension and copy rest of + * string into fname. + */ + if (fname) { + len = __min((p - path), (_MAX_FNAME - 1)); + STRNCPY(fname, path, len); + *(fname + len) = '\0'; + } + if (ext) { + *ext = '\0'; + } + } +} diff --git a/private/crt32/misc/strerror.c b/private/crt32/misc/strerror.c new file mode 100644 index 000000000..ec8c7dd41 --- /dev/null +++ b/private/crt32/misc/strerror.c @@ -0,0 +1,142 @@ +/*** +*strerror.c - Contains the strerror C runtime. +* +* Copyright (c) 1987-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* The strerror runtime accepts an error number as input +* and returns the corresponding error string. +* +* NOTE: The "old" strerror C runtime resides in file _strerr.c +* and is now called _strerror. The new strerror runtime +* conforms to the ANSI standard. +* +*Revision History: +* 02-24-87 JCR Module created. +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-04-87 JCR Improved code. +* 01-05-87 JCR Multi-thread support +* 05-31-88 PHG Merge DLL and normal versions +* 06-06-89 JCR 386 mthread support +* 03-16-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 10-04-90 GJF New-style function declarator. +* 07-18-91 GJF Multi-thread support for Win32 [_WIN32_]. +* 02-17-93 GJF Changed for new _getptd(). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <errmsg.h> +#include <stdlib.h> +#include <syserr.h> +#include <string.h> +#include <os2dll.h> +#ifdef MTHREAD +#include <malloc.h> +#include <stddef.h> +#endif + +/* [NOTE: The mthread error message buffer is shared by both strerror + and _strerror so must be the max length of both. */ +#ifdef MTHREAD +/* Max length of message = user_string(94)+system_string+2 */ +#define _ERRMSGLEN_ 94+_SYS_MSGMAX+2 +#else +/* Max length of message = system_string+2 */ +#define _ERRMSGLEN_ _SYS_MSGMAX+2 +#endif + + +/*** +*char *strerror(errnum) - Map error number to error message string. +* +*Purpose: +* The strerror runtime takes an error number for input and +* returns the corresponding error message string. This routine +* conforms to the ANSI standard interface. +* +*Entry: +* int errnum - Integer error number (corresponding to an errno value). +* +*Exit: +* char * - Strerror returns a pointer to the error message string. +* This string is internal to the strerror routine (i.e., not supplied +* by the user). +* +*Exceptions: +* None. +* +*******************************************************************************/ + +char * _CRTAPI1 strerror ( + int errnum + ) +{ +#ifdef MTHREAD + +#ifdef _CRUISER_ + + struct _tiddata * tdata; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + _ptiddata ptd = _getptd(); + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + char *errmsg; + static char errmsg_backup[_SYS_MSGMAX+2]; + +#else + + static char errmsg[_ERRMSGLEN_]; /* Longest errmsg + \0 */ + +#endif + +#ifdef MTHREAD + +#ifdef _CRUISER_ + + tdata = _gettidtab(); /* get tid's data address */ + if (tdata->_errmsg == NULL) { + if ( (tdata->_errmsg = malloc(_ERRMSGLEN_)) == NULL) + errmsg = errmsg_backup; /* error: use backup */ + else + errmsg = tdata->_errmsg; + } + else + errmsg = tdata->_errmsg; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if ( (ptd->_errmsg == NULL) && ((ptd->_errmsg = malloc(_ERRMSGLEN_)) + == NULL) ) + errmsg = errmsg_backup; /* error: use backup */ + else + errmsg = ptd->_errmsg; + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + +#endif + + strcpy(errmsg, _sys_err_msg(errnum)); + return(errmsg); +} diff --git a/private/crt32/misc/syserr.c b/private/crt32/misc/syserr.c new file mode 100644 index 000000000..ef5ee29ed --- /dev/null +++ b/private/crt32/misc/syserr.c @@ -0,0 +1,85 @@ +/*** +*syserr.c - system error list +* +* Copyright (c) 1987-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the System Error List, containing the full messages for +* all errno values set by the library routines. +* Defines sys_errlist, sys_nerr. +* +*Revision History: +* 08-07-87 PHG removed obsolete definition of sys_msgmax. +* 04-06-90 GJF Added #include <cruntime.h>. Also, fixed the copyright. +* 01-21-91 GJF ANSI naming. +* 07-11-91 JCR Changed "core" to "memory" in ENOMEM message +* 01-23-92 GJF Added #include <stdlib.h> (contains decl of sys_nerr). +* 09-30-92 GJF Made POSIX compatible. Non-POSIX errno values are +* mapped to "Unknown error" for now. Next step is to +* delete these and renumber to eliminate the gaps, after +* the beta release. +* 04-08-93 CFW Added EILSEQ (42) message. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <stdlib.h> + +char *_sys_errlist[] = +{ + /* 0 */ "No error", + /* 1 EPERM */ "Operation not permitted", + /* 2 ENOENT */ "No such file or directory", + /* 3 ESRCH */ "No such process", + /* 4 EINTR */ "Interrupted function call", + /* 5 EIO */ "Input/output error", + /* 6 ENXIO */ "No such device or address", + /* 7 E2BIG */ "Arg list too long", + /* 8 ENOEXEC */ "Exec format error", + /* 9 EBADF */ "Bad file descriptor", + /* 10 ECHILD */ "No child processes", + /* 11 EAGAIN */ "Resource temporarily unavailable", + /* 12 ENOMEM */ "Not enough space", + /* 13 EACCES */ "Permission denied", + /* 14 EFAULT */ "Bad address", + /* 15 ENOTBLK */ "Unknown error", /* not POSIX */ + /* 16 EBUSY */ "Resource device", + /* 17 EEXIST */ "File exists", + /* 18 EXDEV */ "Improper link", + /* 19 ENODEV */ "No such device", + /* 20 ENOTDIR */ "Not a directory", + /* 21 EISDIR */ "Is a directory", + /* 22 EINVAL */ "Invalid argument", + /* 23 ENFILE */ "Too many open files in system", + /* 24 EMFILE */ "Too many open files", + /* 25 ENOTTY */ "Inappropriate I/O control operation", + /* 26 ETXTBSY */ "Unknown error", /* not POSIX */ + /* 27 EFBIG */ "File too large", + /* 28 ENOSPC */ "No space left on device", + /* 29 ESPIPE */ "Invalid seek", + /* 30 EROFS */ "Read-only file system", + /* 31 EMLINK */ "Too many links", + /* 32 EPIPE */ "Broken pipe", + /* 33 EDOM */ "Domain error", + /* 34 ERANGE */ "Result too large", + /* 35 EUCLEAN */ "Unknown error", /* not POSIX */ + /* 36 EDEADLK */ "Resource deadlock avoided", + /* 37 UNKNOWN */ "Unknown error", + /* 38 ENAMETOOLONG */ "Filename too long", + /* 39 ENOLCK */ "No locks available", + /* 40 ENOSYS */ "Function not implemented", + /* 41 ENOTEMPTY */ "Directory not empty", + /* 42 EILSEQ */ "Illegal byte sequence", + /* 43 */ "Unknown error" + +}; + +int _sys_nerr = sizeof( _sys_errlist ) / sizeof( _sys_errlist[ 0 ] ) - 1; + +/* The above array contains all the errors including unknown error # 37 + which is used if msg_num is unknown */ + + +/* ***NOTE: Parameter _SYS_MSGMAX (in file syserr.h) indicates the length of + the longest systerm error message in the above table. When you add or + modify a message, you must update the value _SYS_MSGMAX, if appropriate. */ diff --git a/private/crt32/misc/umask.c b/private/crt32/misc/umask.c new file mode 100644 index 000000000..9ca63a876 --- /dev/null +++ b/private/crt32/misc/umask.c @@ -0,0 +1,55 @@ +/*** +*umask.c - set file permission mask +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _umask() - sets file permission mask of current process* +* affecting files created by creat, open, or sopen. +* +*Revision History: +* 06-02-89 PHG module created +* 03-16-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 04-05-90 GJF Added #include <io.h>. +* 10-04-90 GJF New-style function declarator. +* 01-17-91 GJF ANSI naming. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <internal.h> +#include <io.h> + +/*** +*int _umask(mode) - set the file mode mask +* +*Purpose: +* Sets the file-permission mask of the current process* which +* modifies the permission setting of new files created by creat, +* open, or sopen. +* +*Entry: +* int mode - new file permission mask +* may contain S_IWRITE, S_IREAD, S_IWRITE | S_IREAD. +* The S_IREAD bit has no effect under OS/2. +* +*Exit: +* returns the previous setting of the file permission mask. +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _umask ( + int mode + ) +{ + register int oldmode; /* old umask value */ + + mode &= 0x180; /* only user read/write permitted */ + oldmode = _umaskval; /* remember old value */ + _umaskval = mode; /* set new value */ + return oldmode; /* return old value */ +} diff --git a/private/crt32/misc/winsig.c b/private/crt32/misc/winsig.c new file mode 100644 index 000000000..310f1c62f --- /dev/null +++ b/private/crt32/misc/winsig.c @@ -0,0 +1,709 @@ +/*** +*winsig.c - C signal support +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved +* +*Purpose: +* Defines signal(), raise() and supporting functions. +* +*Revision History: +* 10-21-91 GJF Signal for Win32 and Dosx32. Copied from old signal.c +* (the Cruiser implementation with some revisions for +* Win32), then extensively rewritten. +* 11-08-91 GJF Cleaned up header files usage. +* 12-13-91 GJF Fixed multi-thread build. +* 09-30-92 SRW Add WINAPI keyword to CtrlC handler +* 02-17-93 GJF Changed for new _getptd(). +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <errno.h> +#include <float.h> +#include <malloc.h> +#include <os2dll.h> +#include <oscalls.h> +#include <signal.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +/* + * look up the first entry in the exception-action table corresponding to + * the given signal + */ +#ifdef MTHREAD +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int, struct _XCPT_ACTION *); +#else /* not MTHREAD */ +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int); +#endif /* MTHREAD */ + +/* + * variables holding action codes (and code pointers) for SIGINT, SIGBRK, + * SIGABRT and SIGTERM. + * + * note that the disposition (i.e., action to be taken upon receipt) of + * these signals is defined on a per-process basis (not per-thread)!! + */ + +static _PHNDLR ctrlc_action = SIG_DFL; /* SIGINT */ +static _PHNDLR ctrlbreak_action = SIG_DFL; /* SIGBREAK */ +static _PHNDLR abort_action = SIG_DFL; /* SIGABRT */ +static _PHNDLR term_action = SIG_DFL; /* SIGTERM */ + +/* + * flag indicated whether or not a handler has been installed to capture + * ^C and ^Break events. + */ +static int ConsoleCtrlHandler_Installed = 0; + + +/*** +*static BOOL WINAPI ctrlevent_capture(DWORD CtrlType) - capture ^C and ^Break events +* +*Purpose: +* Capture ^C and ^Break events from the console and dispose of them +* according the values in ctrlc_action and ctrlbreak_action, resp. +* This is the routine that evokes the user-defined action for SIGINT +* (^C) or SIGBREAK (^Break) installed by a call to signal(). +* +*Entry: +* DWORD CtrlType - indicates type of event, two values: +* CTRL_C_EVENT +* CTRL_BREAK_EVENT +* +*Exit: +* Returns TRUE to indicate the event (signal) has been handled. +* Otherwise, returns FALSE. +* +*Exceptions: +* +*******************************************************************************/ + +static BOOL WINAPI ctrlevent_capture ( + DWORD CtrlType + ) +{ + _PHNDLR ctrl_action; + _PHNDLR *pctrl_action; + int sigcode; + + _mlock(_SIGNAL_LOCK); + + /* + * Identify the type of event and fetch the corresponding action + * description. + */ + + if ( CtrlType == CTRL_C_EVENT ) { + ctrl_action = *(pctrl_action = &ctrlc_action); + sigcode = SIGINT; + } + else { + ctrl_action = *(pctrl_action = &ctrlbreak_action); + sigcode = SIGBREAK; + } + + if ( ctrl_action == SIG_DFL ) { + /* + * return FALSE, indicating the event has NOT been handled + */ + _munlock(_SIGNAL_LOCK); + return FALSE; + } + + if ( ctrl_action != SIG_IGN ) { + /* + * Reset the action to be SIG_DFL and call the user's handler. + */ + *pctrl_action = SIG_DFL; + _munlock(_SIGNAL_LOCK); + (*ctrl_action)(sigcode); + } + else + /* + * SIG_IGN - nothing special to do except release the lock + */ + _munlock(_SIGNAL_LOCK); + + /* + * Return TRUE, indicating the event has been handled (which may + * mean it's being ignored) + */ + return TRUE; +} + + + +/*** +*_PHNDLR signal(signum, sigact) - Define a signal handler +* +*Purpose: +* The signal routine allows the user to define what action should +* be taken when various signals occur. The Win32/Dosx32 implementation +* supports seven signals, divided up into three general groups +* +* 1. Signals corresponding to OS exceptions. These are: +* SIGFPE +* SIGILL +* SIGSEGV +* Signal actions for these signals are installed by altering the +* XcptAction and SigAction fields for the appropriate entry in the +* exception-action table (XcptActTab[]). +* +* 2. Signals corresponding to ^C and ^Break. These are: +* SIGINT +* SIGBREAK +* Signal actions for these signals are installed by altering the +* _ctrlc_action and _ctrlbreak_action variables. +* +* 3. Signals which are implemented only in the runtime. That is, they +* occur only as the result of a call to raise(). +* SIGABRT +* SIGTERM +* +* +*Entry: +* int signum signal type. recognized signal types are: +* +* SIGABRT (ANSI) +* SIGBREAK +* SIGFPE (ANSI) +* SIGILL (ANSI) +* SIGINT (ANSI) +* SIGSEGV (ANSI) +* SIGTERM (ANSI) +* +* _PHNDLR sigact signal handling function or action code. the action +* codes are: +* +* SIG_DFL - take the default action, whatever that may +* be, upon receipt of this type type of signal. +* +* SIG_DIE - *** ILLEGAL *** +* special code used in the XcptAction field of an +* XcptActTab[] entry to indicate that the runtime is +* to terminate the process upon receipt of the exception. +* not accepted as a value for sigact. +* +* SIG_IGN - ignore this type of signal +* +* [function address] - transfer control to this address +* when a signal of this type occurs. +* +*Exit: +* Good return: +* Signal returns the previous value of the signal handling function +* (e.g., SIG_DFL, SIG_IGN, etc., or [function address]). This value is +* returned in DX:AX. +* +* Error return: +* Signal returns -1 and errno is set to EINVAL. The error return is +* generally taken if the user submits bogus input values. +* +*Exceptions: +* None. +* +*******************************************************************************/ + +_PHNDLR _CRTAPI1 signal( + int signum, + _PHNDLR sigact + ) +{ + struct _XCPT_ACTION *pxcptact; + _PHNDLR oldsigact; +#ifdef MTHREAD + _ptiddata ptd; +#endif + + /* + * Check for values of sigact supported on other platforms but not + * on this one. Also, make sure sigact is not SIG_DIE + */ + if ( (sigact == SIG_ACK) || (sigact == SIG_SGE) ) + goto sigreterror; + + /* + * Take care of all signals which do not correspond to exceptions + * in the host OS. Those are: + * + * SIGINT + * SIGBREAK + * SIGABRT + * SIGTERM + * + */ + if ( (signum == SIGINT) || (signum == SIGBREAK) || (signum == SIGABRT) + || (signum == SIGTERM) ) { + + _mlock(_SIGNAL_LOCK); + + /* + * if SIGINT or SIGBREAK, make sure the handler is installed + * to capture ^C and ^Break events. + */ + if ( ((signum == SIGINT) || (signum == SIGBREAK)) && + !ConsoleCtrlHandler_Installed ) + if ( SetConsoleCtrlHandler(ctrlevent_capture, TRUE) + == TRUE ) + ConsoleCtrlHandler_Installed = TRUE; + else { + _doserrno = GetLastError(); + _munlock(_SIGNAL_LOCK); + goto sigreterror; + } + + switch (signum) { + + case SIGINT: + oldsigact = ctrlc_action; + ctrlc_action = sigact; + break; + + case SIGBREAK: + oldsigact = ctrlbreak_action; + ctrlbreak_action = sigact; + break; + + case SIGABRT: + oldsigact = abort_action; + abort_action = sigact; + break; + + case SIGTERM: + oldsigact = term_action; + term_action = sigact; + break; + } + + _munlock(_SIGNAL_LOCK); + goto sigretok; + } + + /* + * If we reach here, signum is supposed to be one the signals which + * correspond to exceptions in the host OS. Those are: + * + * SIGFPE + * SIGILL + * SIGSEGV + */ + + /* + * Make sure signum is one of the remaining supported signals. + */ + if ( (signum != SIGFPE) && (signum != SIGILL) && (signum != SIGSEGV) ) + goto sigreterror; + + +#ifdef MTHREAD + /* + * Fetch the tid data table entry for this thread + */ + ptd = _getptd(); + + /* + * Check that there a per-thread instance of the exception-action + * table for this thread. if there isn't, create one. + */ + if ( ptd->_pxcptacttab == _XcptActTab ) + /* + * allocate space for an exception-action table + */ + if ( (ptd->_pxcptacttab = malloc(_XcptActTabSize)) + != NULL ) + /* + * initialize the table by copying over the contents + * of _XcptActTab[] + */ + (void) memcpy(ptd->_pxcptacttab, _XcptActTab, + _XcptActTabSize); + else + /* + * cannot create exception-action table, return + * error to caller + */ + goto sigreterror; + +#endif /* MTHREAD */ + + /* + * look up the proper entry in the exception-action table. note that + * if several exceptions are mapped to the same signal, this returns + * the pointer to first such entry in the exception action table. it + * is assumed that the other entries immediately follow this one. + */ +#ifdef MTHREAD + if ( (pxcptact = siglookup(signum, ptd->_pxcptacttab)) == NULL ) +#else /* not MTHREAD */ + if ( (pxcptact = siglookup(signum)) == NULL ) +#endif /* MTHREAD */ + goto sigreterror; + + /* + * SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped + * to them. the code below depends on the exceptions corresponding to + * the same signal being grouped together in the exception-action + * table. + */ + + /* + * store old signal action code for return value + */ + oldsigact = pxcptact->XcptAction; + + /* + * loop through all entries corresponding to the + * given signal and update the SigAction and XcptAction + * fields as appropriate + * + * should add a test to make sure pxcptact never runs + * off the end of the table (works okay for now because + * of the order of the entries). + */ + while ( pxcptact->SigNum == signum ) { + /* + * take care of the SIG_IGN and SIG_DFL action + * codes + */ + pxcptact->XcptAction = sigact; + pxcptact++; + } + +sigretok: + return(oldsigact); + +sigreterror: + errno = EINVAL; + return(SIG_ERR); +} + +/*** +*int raise(signum) - Raise a signal +* +*Purpose: +* This routine raises a signal (i.e., performs the action currently +* defined for this signal). The action associated with the signal is +* evoked directly without going through intermediate dispatching or +* handling. +* +*Entry: +* int signum - signal type (e.g., SIGINT) +* +*Exit: +* returns 0 on good return, -1 on bad return. +* +*Exceptions: +* May not return. Raise has no control over the action +* routines defined for the various signals. Those routines may +* abort, terminate, etc. In particular, the default actions for +* certain signals will terminate the program. +* +*******************************************************************************/ + + +int _CRTAPI1 raise ( + int signum + ) +{ + _PHNDLR sigact; + _PHNDLR *psigact; + PEXCEPTION_POINTERS oldpxcptinfoptrs; + int oldfpecode; + +#ifdef MTHREAD + int siglock = 0; + _ptiddata ptd; +#endif + + switch (signum) { + + case SIGINT: + sigact = *(psigact = &ctrlc_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGBREAK: + sigact = *(psigact = &ctrlbreak_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGABRT: + sigact = *(psigact = &abort_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGTERM: + sigact = *(psigact = &term_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGFPE: + case SIGILL: + case SIGSEGV: +#ifdef MTHREAD + ptd = _getptd(); + sigact = *(psigact = &(siglookup( signum, + ptd->_pxcptacttab )->XcptAction)); +#else + sigact = *(psigact = &(siglookup( signum )-> + XcptAction)); +#endif + break; + + default: + /* + * unsupported signal, return an error + */ + return (-1); + } + +#ifdef MTHREAD + /* + * if signum is one of the 'process-wide' signals (i.e., SIGINT, + * SIGBREAK, SIGABRT or SIGTERM), assert _SIGNAL_LOCK. + */ + if ( siglock ) + _mlock(_SIGNAL_LOCK); +#endif + + /* + * If the current action is SIG_IGN, just return + */ + if ( sigact == SIG_IGN ) { + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + return(0); + } + + /* + * If the current action is SIG_DFL, take the default action + */ + if ( sigact == SIG_DFL ) { + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + /* + * The current default action for all of the supported + * signals is to terminate with an exit code of 3. + * + * BUG, BUG!!!! THIS IS ALMOST CERTAINLY THE WRONG EXIT + * CODE FOR SOME OF THE SIGNALS IN NT! + */ + _exit(3); + } + + /* + * From here on, sigact is assumed to be a pointer to a user-supplied + * handler. + */ + + /* + * For signals which correspond to exceptions, set the pointer + * to the EXCEPTION_POINTERS structure to NULL + */ + if ( (signum == SIGFPE) || (signum == SIGSEGV) || + (signum == SIGILL) ) { +#ifdef MTHREAD + oldpxcptinfoptrs = ptd->_tpxcptinfoptrs; + ptd->_tpxcptinfoptrs = NULL; +#else + oldpxcptinfoptrs = _pxcptinfoptrs; + _pxcptinfoptrs = NULL; +#endif + + /* + * If signum is SIGFPE, also set _fpecode to + * _FPE_EXPLICITGEN + */ + if ( signum == SIGFPE ) { +#ifdef MTHREAD + oldfpecode = ptd->_tfpecode; + ptd->_tfpecode = _FPE_EXPLICITGEN; +#else + oldfpecode = _fpecode; + _fpecode = _FPE_EXPLICITGEN; +#endif + } + } + + /* + * Reset the action to SIG_DFL and call the user specified handler + * routine. + */ + *psigact = SIG_DFL; + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + + if ( signum == SIGFPE ) + /* + * Special hack to support old SIGFPE handlers which + * expect the value of _fpecode as the second argument. + */ +#ifdef MTHREAD + (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE, + ptd->_tfpecode); +#else + (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE, _fpecode); +#endif + else + (*sigact)(signum); + + /* + * For signals which correspond to exceptions, restore the pointer + * to the EXCEPTION_POINTERS structure. + */ + if ( (signum == SIGFPE) || (signum == SIGSEGV) || + (signum == SIGILL) ) { +#ifdef MTHREAD + ptd->_tpxcptinfoptrs = oldpxcptinfoptrs; +#else + _pxcptinfoptrs = oldpxcptinfoptrs; +#endif + + /* + * If signum is SIGFPE, also restore _fpecode + */ + if ( signum == SIGFPE ) +#ifdef MTHREAD + ptd->_tfpecode = oldfpecode; +#else + _fpecode = oldfpecode; +#endif + } + + return(0); +} + + +/*** +*struct _XCPT_ACTION *siglookup(int signum) - look up exception-action table +* entry for signal. +* +*Purpose: +* Find the first entry int _XcptActTab[] whose SigNum field is signum. +* +*Entry: +* int signum - C signal type (e.g., SIGINT) +* +*Exit: +* If successful, pointer to the table entry. If no such entry, NULL is +* returned. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 siglookup ( + int signum, + struct _XCPT_ACTION *pxcptacttab + ) +{ + struct _XCPT_ACTION *pxcptact = pxcptacttab; + +#else /* not MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int signum) +{ + struct _XCPT_ACTION *pxcptact = _XcptActTab; + +#endif /* MTHREAD */ + /* + * walk thru the _xcptactab table looking for the proper entry. note + * that in the case where more than one exception corresponds to the + * same signal, the first such instance in the table is the one + * returned. + */ +#ifdef MTHREAD + + while ( (pxcptact->SigNum != signum) && (++pxcptact < + pxcptacttab + _XcptActTabCount) ) ; + +#else /* not MTHREAD */ + + while ( (pxcptact->SigNum != signum) && (++pxcptact < + _XcptActTab + _XcptActTabCount) ) ; + +#endif /* MTHREAD */ + + if ( pxcptact->SigNum == signum ) + /* + * found a table entry corresponding to the signal + */ + return(pxcptact); + else + /* + * found no table entry corresponding to the signal + */ + return(NULL); +} + +#ifdef MTHREAD + +/*** +*int *__fpecode(void) - return pointer to _fpecode field of the tidtable entry +* for the current thread +* +*Purpose: +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +int * _CRTAPI1 __fpecode ( + void + ) +{ + return( &(_getptd()->_tfpecode) ); +} + + +/*** +*void **__pxcptinfoptrs(void) - return pointer to _pxcptinfoptrs field of the +* tidtable entry for the current thread +* +*Purpose: +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +void ** _CRTAPI1 __pxcptinfoptrs ( + void + ) +{ + return( &(_getptd()->_tpxcptinfoptrs) ); +} + +#endif + +#endif /* _POSIX_ */ diff --git a/private/crt32/misc/winxfltr.c b/private/crt32/misc/winxfltr.c new file mode 100644 index 000000000..22b4f08f4 --- /dev/null +++ b/private/crt32/misc/winxfltr.c @@ -0,0 +1,618 @@ +/*** +*winxfltr.c - startup exception filter +* +* Copyright (c) 1990-1993, Microsoft Corporation. All rights reserved +* +*Purpose: +* Defines _XcptFilter(), the function called by the exception filter +* expression in the startup code. +* +*Revision History: +* 10-31-91 GJF Module created. Copied from the original xcptfltr.c +* then extensively revised. +* 11-08-91 GJF Cleaned up header files usage. +* 12-13-91 GJF Fixed multi-thread build. +* 01-17-92 GJF Changed default handling under Win32 - unhandled +* exceptions are now passed to UnhandledExceptionFilter. +* Dosx32 behavior in unchanged. Also, used a couple of +* local macros to simplify handling of single-thread vs +* multi-thread code [_Win32_]. +* 02-16-93 GJF Changed for new _getptd(). +* 04-27-93 GJF Removed (commented out) entries in _XcptActTab which +* corresponded to C RTEs. These will now simply be +* passed on through to the system exception handler. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <float.h> +#include <os2dll.h> +#include <oscalls.h> +#include <signal.h> +#include <stddef.h> + + +/* + * special code denoting no signal. + */ +#define NOSIG -1 + + +struct _XCPT_ACTION _VARTYPE1 _XcptActTab[] = { + +/* + * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped + * together. + * + * XcptNum SigNum XcptAction + * ------------------------------------------------------------------- + */ + { (unsigned long)STATUS_ACCESS_VIOLATION, SIGSEGV, SIG_DFL }, + + { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, SIGILL, SIG_DFL }, + + { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, SIGILL, SIG_DFL }, + +/* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE }, + */ +/* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE }, + */ + { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_OVERFLOW, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_STACK_CHECK, SIGFPE, SIG_DFL }, + + { (unsigned long)STATUS_FLOAT_UNDERFLOW, SIGFPE, SIG_DFL }, + +/* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG, SIG_DIE }, + */ +/* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG, SIG_DIE } + */ +}; + +/* + * size of the exception-action table (in bytes) + */ +int _CRTVAR1 _XcptActTabSize = sizeof _XcptActTab; + +/* + * number of entries in the exception-action table + */ +int _CRTVAR1 _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]); + + +#ifdef MTHREAD + +/* + * the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of + * single vs multi-thread code in the filter function. basically, each macro + * is conditionally defined to be a global variable or the corresponding + * field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE + * _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!! + */ + +#define FPECODE ptd->_tfpecode + +#define PXCPTINFOPTRS ptd->_tpxcptinfoptrs + +#else + +/* + * global variable containing the floating point exception code + */ +int _VARTYPE1 _fpecode = _FPE_EXPLICITGEN; + +#define FPECODE _fpecode + +/* + * global variable holding _PEXCEPTION_INFO_PTRS value + */ +void * _VARTYPE1 _pxcptinfoptrs = NULL; + +#define PXCPTINFOPTRS _pxcptinfoptrs + +#endif /* MTHREAD */ + +/* + * function to look up the exception action table (_XcptActTab[]) corresponding + * to the given exception + */ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup( + unsigned long, + struct _XCPT_ACTION * + ); + +#else /* ndef MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup( + unsigned long + ); + +#endif /* MTHREAD */ + +#ifdef DEBUG + +/* + * prototypes for debugging routines + */ +void prXcptActTabEntry(struct _XCPT_ACTION *); +void prXcptActTab(void); + +#endif /* DEBUG */ + +/*** +*int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to +* be taken with it +* +*Purpose: +* _XcptFilter() is called by the exception filter expression of the +* _try - _except statement, in the startup code, which guards the call +* to the user's main(). _XcptFilter() consults the _XcptActTab[] table +* to identify the exception and determine its disposition. The +* is disposition of an exception corresponding to a C signal may be +* modified by a call to signal(). There are three broad cases: +* +* (1) Unrecognized exceptions and exceptions for which the XcptAction +* value is SIG_DFL. +* +#ifndef DOSX32 +* In both of these cases, UnhandledExceptionFilter() is called and +* its return value is returned. +#else +* In both of these cases, EXCEPTION_CONTINUE_SEARCH is returned to +* cause the OS exception dispatcher to pass the exception onto the +* next exception handler in the chain (usually a system default +* handler). +#endif +* +* (2) Exceptions corresponding to C signals with an XcptAction value +* NOT equal to SIG_DFL. +* +* These are the C signals whose disposition has been affected by a +* call to signal() or whose default semantics differ slightly from +* from the corresponding OS exception. In all cases, the appropriate +* disposition of the C signal is made by the function (e.g., calling +* a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU- +* TION is returned to cause the OS exception dispatcher to dismiss +* the exception and resume execution at the point where the +* exception occurred. +* +* (3) Exceptions for which the XcptAction value is SIG_DIE. +* +* These are the exceptions corresponding to fatal C runtime errors. +* _XCPT_HANDLE is returned to cause control to pass into the +* _except-block of the _try - _except statement. There, the runtime +* error is identified, an appropriate error message is printed out +* and the program is terminated. +* +*Entry: +* +*Exit: +* +*Exceptions: +* That's what it's all about! +* +*******************************************************************************/ + +int _CRTAPI1 _XcptFilter ( + unsigned long xcptnum, + PEXCEPTION_POINTERS pxcptinfoptrs + ) +{ + struct _XCPT_ACTION * pxcptact; + _PHNDLR phandler; + void *oldpxcptinfoptrs; + int oldfpecode; + +#ifdef MTHREAD + _ptiddata ptd = _getptd(); +#endif /* MTHREAD */ + + /* + * first, take care of all unrecognized exceptions and exceptions with + * XcptAction values of SIG_DFL. + */ +#ifdef MTHREAD + if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL) + || (pxcptact->XcptAction == SIG_DFL) ) +#else /* not MTHREAD */ + if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) || + (pxcptact->XcptAction == SIG_DFL) ) +#endif /* MTHREAD */ + +#ifndef DOSX32 + /* + * pass the buck to the UnhandledExceptionFilter + */ + return( UnhandledExceptionFilter(pxcptinfoptrs) ); +#else + /* + * pass the buck to the next level exception handler + */ + return(EXCEPTION_CONTINUE_SEARCH); +#endif + +#ifdef DEBUG + prXcptActTabEntry(pxcptact); +#endif /* DEBUG */ + + /* + * next, weed out all of the exceptions that need to be handled by + * dying, perhaps with a runtime error message + */ + if ( pxcptact->XcptAction == SIG_DIE ) { + /* + * reset XcptAction (in case of recursion) and drop into the + * except-clause. + */ + pxcptact->XcptAction = SIG_DFL; + return(EXCEPTION_EXECUTE_HANDLER); + } + + /* + * next, weed out all of the exceptions that are simply ignored + */ + if ( pxcptact->XcptAction == SIG_IGN ) + /* + * resume execution + */ + return(EXCEPTION_CONTINUE_EXECUTION); + + /* + * the remaining exceptions all correspond to C signals which have + * signal handlers associated with them. for some, special setup + * is required before the signal handler is called. in all cases, + * if the signal handler returns, -1 is returned by this function + * to resume execution at the point where the exception occurred. + * + * before calling the signal handler, the XcptAction field of the + * exception-action table entry must be reset. + */ + phandler = pxcptact->XcptAction; + + /* + * reset the action to be the default + */ + pxcptact->XcptAction = SIG_DFL; + + /* + * save the old value of _pxcptinfoptrs (in case this is a nested + * exception/signal) and store the current one. + */ + oldpxcptinfoptrs = PXCPTINFOPTRS; + PXCPTINFOPTRS = pxcptinfoptrs; + + /* + * call the user-supplied signal handler + * + * floating point exceptions must be handled specially since, from + * the C point-of-view, there is only one signal. the exact identity + * of the exception is passed in the global variable _fpecode. + */ + if ( pxcptact->SigNum == SIGFPE ) { + /* + * Save the current _fpecode in case it is a nested floating + * point exception (not clear that we need to support this, + * but it's easy). + */ + oldfpecode = FPECODE; + + /* + * there are no exceptions corresponding to + * following _FPE_xxx codes: + * + * _FPE_UNEMULATED + * _FPE_SQRTNEG + * + * futhermore, STATUS_FLOATING_STACK_CHECK is + * raised for both floating point stack under- + * flow and overflow. thus, the exception does + * not distinguish between _FPE_STACKOVERLOW + * and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode + * is set to the former value. + * + * the following should be a switch statement but, alas, the + * compiler doesn't like switching on unsigned longs... + */ + if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO ) + + FPECODE = _FPE_ZERODIVIDE; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION ) + + FPECODE = _FPE_INVALID; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW ) + + FPECODE = _FPE_OVERFLOW; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW ) + + FPECODE = _FPE_UNDERFLOW; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND ) + + FPECODE = _FPE_DENORMAL; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT ) + + FPECODE = _FPE_INEXACT; + + else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK ) + + FPECODE = _FPE_STACKOVERFLOW; + + /* + * call the SIGFPE handler. note the special hack to support + * old MS-C programs whose SIGFPE handlers expect two args. + * + * NOTE: THE CAST AND CALL BELOW DEPEND ON _CRTAPI1 BEING + * CALLER CLEANUP! + */ + (*(void (* _CRTAPI1)(int, int))phandler)(SIGFPE, FPECODE); + + /* + * restore the old value of _fpecode + */ + FPECODE = oldfpecode; + } + else + (*phandler)(pxcptact->SigNum); + + /* + * restore the old value of _pxcptinfoptrs + */ + PXCPTINFOPTRS = oldpxcptinfoptrs; + + return(EXCEPTION_CONTINUE_EXECUTION); + +} + + +/*** +*struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action +* table entry for xcptnum +* +*Purpose: +* Find the in _XcptActTab[] whose Xcptnum field is xcptnum. +* +*Entry: +* unsigned long xcptnum - exception type +* +* _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record +* (used only to distinguish different types of XCPT_SIGNAL) +* +*Exit: +* If successful, pointer to the table entry. If no such entry, NULL is +* returned. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup ( + unsigned long xcptnum, + struct _XCPT_ACTION * pxcptacttab + ) + +#else /* not MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 xcptlookup ( + unsigned long xcptnum + ) + +#endif /* MTHREAD */ + +{ +#ifdef MTHREAD + struct _XCPT_ACTION *pxcptact = pxcptacttab; +#else /* ndef MTHREAD */ + struct _XCPT_ACTION *pxcptact = _XcptActTab; +#endif /* MTHREAD */ + + /* + * walk thru the _xcptactab table looking for the proper entry + */ +#ifdef MTHREAD + + while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact < + pxcptacttab + _XcptActTabCount) ) ; + +#else /* not MTHREAD */ + + while ( (pxcptact->XcptNum != xcptnum) && (++pxcptact < + _XcptActTab + _XcptActTabCount) ) ; + +#endif /* MTHREAD */ + + /* + * if no table entry was found corresponding to xcptnum, return NULL + */ + if ( pxcptact->XcptNum != xcptnum ) + return(NULL); + + return(pxcptact); +} + +#ifdef DEBUG + +/* + * DEBUGGING TOOLS! + */ +struct xcptnumstr { + unsigned long num; + char *str; +}; + +struct xcptnumstr XcptNumStr[] = { + + { (unsigned long)STATUS_DATATYPE_MISALIGNMENT, + "STATUS_DATATYPE_MISALIGNMENT" }, + + { (unsigned long)STATUS_ACCESS_VIOLATION, + "STATUS_ACCESS_VIOLATION" }, + + { (unsigned long)STATUS_ILLEGAL_INSTRUCTION, + "STATUS_ILLEGAL_INSTRUCTION" }, + + { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, + "STATUS_NONCONTINUABLE_EXCEPTION" }, + + { (unsigned long)STATUS_INVALID_DISPOSITION, + "STATUS_INVALID_DISPOSITION" }, + + { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, + "STATUS_FLOAT_DENORMAL_OPERAND" }, + + { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, + "STATUS_FLOAT_DIVIDE_BY_ZERO" }, + + { (unsigned long)STATUS_FLOAT_INEXACT_RESULT, + "STATUS_FLOAT_INEXACT_RESULT" }, + + { (unsigned long)STATUS_FLOAT_INVALID_OPERATION, + "STATUS_FLOAT_INVALID_OPERATION" }, + + { (unsigned long)STATUS_FLOAT_OVERFLOW, + "STATUS_FLOAT_OVERFLOW" }, + + { (unsigned long)STATUS_FLOAT_STACK_CHECK, + "STATUS_FLOAT_STACK_CHECK" }, + + { (unsigned long)STATUS_FLOAT_UNDERFLOW, + "STATUS_FLOAT_UNDERFLOW" }, + + { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, + "STATUS_INTEGER_DIVIDE_BY_ZERO" }, + + { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, + "STATUS_PRIVILEGED_INSTRUCTION" }, + + { (unsigned long)_STATUS_STACK_OVERFLOW, + "_STATUS_STACK_OVERFLOW" } +}; + +#define XCPTNUMSTR_SZ ( sizeof XcptNumStr / sizeof XcptNumStr[0] ) + +/* + * return string mnemonic for exception + */ +char * XcptNumToStr ( + unsigned long xcptnum + ) +{ + int indx; + + for ( indx = 0 ; indx < XCPTNUMSTR_SZ ; indx++ ) + if ( XcptNumStr[indx].num == xcptnum ) + return(XcptNumStr[indx].str); + + return(NULL); +} + +struct signumstr { + int num; + char *str; +}; + +struct signumstr SigNumStr[] = { + { SIGINT, "SIGINT" }, + { SIGILL, "SIGILL" }, + { SIGFPE, "SIGFPE" }, + { SIGSEGV, "SIGSEGV" }, + { SIGTERM, "SIGTERM" }, + { SIGBREAK, "SIGBREAK" }, + { SIGABRT, "SIGABRT" } +}; + +#define SIGNUMSTR_SZ ( sizeof SigNumStr / sizeof SigNumStr[0] ) + +/* + * return string mnemonic for signal + */ +char * SigNumToStr ( + int signum + ) +{ + int indx; + + for ( indx = 0 ; indx < SIGNUMSTR_SZ ; indx++ ) + if ( SigNumStr[indx].num == signum ) + return(SigNumStr[indx].str); + + return(NULL); +} + +struct actcodestr { + _PHNDLR code; + char *str; +}; + +struct actcodestr ActCodeStr[] = { + { SIG_DFL, "SIG_DFL" }, + { SIG_IGN, "SIG_IGN" }, + { SIG_DIE, "SIG_DIE" } +}; + +#define ACTCODESTR_SZ ( sizeof ActCodeStr / sizeof ActCodeStr[0] ) + +/* + * return string mnemonic for action code + */ +char * ActCodeToStr ( + _PHNDLR action + ) +{ + int indx; + + for ( indx = 0 ; indx < ACTCODESTR_SZ ; indx++ ) + if ( ActCodeStr[indx].code == action) + return(ActCodeStr[indx].str); + + return("FUNCTION ADDRESS"); +} + +/* + * print out exception-action table entry + */ +void prXcptActTabEntry ( + struct _XCPT_ACTION *pxcptact + ) +{ + printf("XcptNum = %s\n", XcptNumToStr(pxcptact->XcptNum)); + printf("SigNum = %s\n", SigNumToStr(pxcptact->SigNum)); + printf("XcptAction = %s\n", ActCodeToStr(pxcptact->XcptAction)); +} + +/* + * print out all entries in the exception-action table + */ +void prXcptActTab ( + void + ) +{ + int indx; + + for ( indx = 0 ; indx < _XcptActTabCount ; indx++ ) { + printf("\n_XcptActTab[%d] = \n", indx); + prXcptActTabEntry(&_XcptActTab[indx]); + } +} + +#endif /* DEBUG */ + +#endif /* _POSIX_ */ diff --git a/private/crt32/misc/wrt2err.c b/private/crt32/misc/wrt2err.c new file mode 100644 index 000000000..40ebe675a --- /dev/null +++ b/private/crt32/misc/wrt2err.c @@ -0,0 +1,84 @@ +/*** +*wrt2err.c - write an LSTRING to stderr (OS/2 version) +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This module contains a routine __wrt2err that writes an LSTRING +* (one byte length followed by the several bytes of the string) +* to the standard error handle (2). This is a helper routine used +* for MATH error messages (and also FORTRAN error messages). It +* is in the C library rather than the math library because there +* are separate MS-DOS and MS OS/2 versions. +* +*Revision History: +* 06-30-89 PHG module created, based on asm version +* 03-16-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and fixed the copyright. Also, cleaned +* up the formatting a bit. +* 07-24-90 SBM Removed '32' from API names +* 10-04-90 GJF New-style function declarator. +* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h> +* 04-26-91 SRW Removed level 3 warnings +* 07-18-91 GJF Replaced call to DbgPrint with WriteFile to standard +* error handle [_WIN32_]. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <oscalls.h> +#include <internal.h> + +/*** +*__wrt2err(msg) - write an LSTRING to stderr +* +*Purpose: +* Takes a near pointer in BX, which is a pointer to an LSTRING which +* is to be written to standard error. An LSTRING is a one-byte length +* followed by that many bytes for the character string (as opposed to +* a null-terminated string). +* +*Entry: +* char *msg = pointer to LSTRING to write to standard error. +* +*Exit: +* Nothing returned. +* +*Exceptions: +* None handled. +* +*******************************************************************************/ + +void __wrt2err ( + char *msg + ) +{ + unsigned long length; /* length of string to write */ + unsigned long numwritten; /* number of bytes written */ + + length = *msg++; /* 1st byte is length */ + + /* write the message to stderr */ +#ifdef _CRUISER_ + + DOSWRITE(2, msg, length, &numwritten); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + WriteFile((HANDLE)_osfhnd[2], msg, length, &numwritten, NULL); + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ +} + +#endif /* _POSIX_ */ + |