;*****************************************************************************
;*
;*                            Open Watcom Project
;*
;*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;*  ========================================================================
;*
;*    This file contains Original Code and/or Modifications of Original
;*    Code as defined in and that are subject to the Sybase Open Watcom
;*    Public License version 1.0 (the 'License'). You may not use this file
;*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;*    provided with the Original Code and Modifications, and is also
;*    available at www.sybase.com/developer/opensource.
;*
;*    The Original Code and all software distributed under the License are
;*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;*    NON-INFRINGEMENT. Please see the License for the specific language
;*    governing rights and limitations under the License.
;*
;*  ========================================================================
;*
;* Description:  Intel 386 implementation strcmp().
;*
;*****************************************************************************


include mdef.inc
include struct.inc

ifdef _PROFILE
include p5prof.inc
endif

        modstart _strcmp,para

cmp4    macro   off
        mov     ebx,off[eax]            ; get dword from op1
        mov     ecx,off[edx]            ; get dword from op2
        cmp     ecx,ebx                 ; compare them
        jne     unequal                 ; quit if not equal
        ife     off-12
         add    eax,off+4               ; point to next group of dwords
         add    edx,off+4               ; ...
        endif
        not     ecx                     ; ...
        add     ebx,0FEFEFEFFh          ; determine if '\0' is one of bytes
        and     ebx,ecx                 ; ...
        and     ebx,80808080h           ; ebx will be non-zero if '\0' found
        endm

        defpe   strcmp
        xdefp   "C",strcmp
    ifdef _PROFILE
        P5Prolog
    endif
    ifdef __STACK__
        mov     eax,4[esp]              ; get p1
        mov     edx,8[esp]              ; get p2
    endif
        cmp     eax,edx                 ; pointers equal ?
        je      equalnorst              ; yes, return 0
    ifndef __STACK__
        push    ecx                     ; save register
    endif
        test    al,3                    ; p1 aligned ?
        jne     realign                 ; no, go and realign
        test    dl,3                    ; p2 aligned ?
        jne     slowcpy                 ; no, do the slow copy (impossible to align both)

fastcpy:
        push    ebx                     ; save register

        align   4
        _loop                           ; - loop
          cmp4  0                       ; - - compare first dword
          _quif ne                      ; - - quit if end of string
          cmp4  4                       ; - - compare second dword
          _quif ne                      ; - - quit if end of string
          cmp4  8                       ; - - compare third dword
          _quif ne                      ; - - quit if end of string
          cmp4  12                      ; - - compare fourth dword
        _until  ne                      ; - until end of string
equalrst:                               ; strings equal, restore registers
        pop     ebx                     ; restore register
    ifndef __STACK__
        pop     ecx                     ; ...
    endif
equalnorst:                             ; strings equal, skip register restore
        sub     eax,eax                 ; indicate strings equal
    ifdef _PROFILE
        P5Epilog
    endif
        ret                             ; return

unequal:                                ; dword was not equal
        _guess                          ; guess strings are equal
          cmp   bl,cl                   ; - check low bytes
          _quif ne                      ; - quit if not equal
          cmp   bl,0                    ; - stop if end of string
          je    equalrst                ; - ...
          cmp   bh,ch                   ; - check next bytes
          _quif ne                      ; - quit if not equal
          cmp   bh,0                    ; - stop if end of string
          je    equalrst                ; - ...
          shr   ebx,16                  ; - shift top 2 bytes to bottom
          shr   ecx,16                  ; - ...
          cmp   bl,cl                   ; - check third byte
          _quif ne                      ; - quit if not equal
          cmp   bl,0                    ; - stop if end of string
          je    equalrst                ; - ...
          cmp   bh,ch                   ; - check high order byte
;;        we know at this point that bh != ch, just have to do the compare
;;        _quif ne                      ; - quit if not equal
;;        cmp   bh,0                    ; - stop if end of string
;;        je    equalrst                ; - ...
        _endguess                       ; endguess
        sbb     eax,eax                 ; eax = 0 if op1>op2, -1 if op1<op2
        or      al,1                    ; eax = 1 if op1>op2, -1 if op1<op2
        pop     ebx                     ; restore registers
    ifndef __STACK__
        pop     ecx                     ; ...
    endif
    ifdef _PROFILE
        P5Epilog
    endif
        ret                             ; return

        align   4
realign:
        _loop                           ; - loop
          mov   cl,[eax]                ; get byte from p1
          inc   eax                     ; point to next byte
          mov   ch,[edx]                ; get byte from p2
          inc   edx                     ; point to next byte
          cmp   cl,ch                   ; bytes equal?
          jne   unequal2                ; unequal, quit
          or    cl,cl                   ; end of string ?
          je    equal2                  ; yes, quit
          test  al,3                    ; check alignment
        _until  e                       ; until aligned
        test    dl,3                    ; p2 aligned ?
        je fastcpy                      ; yes

        align   4
slowcpy:
        _loop
          mov   ecx,[eax]               ; get aligned 4 bytes
          cmp   cl,[edx]                ; check 1st byte
          jne   unequal2                ; bytes not equal
          or    cl,cl                   ; end of string?
          je    equal2                  ; yes, quit
          cmp   ch,[edx+1]              ; check 2nd byte
          jne   unequal2                ; bytes not equal
          or    ch,ch                   ; end of string?
          je    equal2                  ; yes, quit
          shr   ecx,16                  ; move next pair of bytes to be tested
          cmp   cl,[edx+2]              ; check 3rd byte
          jne   unequal2                ; bytes not equal
          or    cl,cl                   ; end of string?
          je    equal2                  ; yes, quit
          cmp   ch,[edx+3]              ; check 4th byte
          jne   unequal2                ; bytes not equal
          or    ch,ch                   ; end of string?
          je    equal2                  ; yes, quit
          mov   ecx,[eax+4]             ; get next aligned 4 bytes
          cmp   cl,[edx+4]              ; check 5th byte
          jne   unequal2                ; bytes not equal
          or    cl,cl                   ; end of string?
          je    equal2                  ; yes, quit
          cmp   ch,[edx+5]              ; check 6th byte
          jne   unequal2                ; bytes not equal
          or    ch,ch                   ; end of string?
          je    equal2                  ; yes, quit
          shr   ecx,16                  ; move next pair of bytes to be tested
          cmp   cl,[edx+6]              ; check 7th byte
          jne   unequal2                ; bytes not equal
          or    cl,cl                   ; end of string?
          je    equal2                  ; yes, quit
          cmp   ch,[edx+7]              ; check 8th byte
          jne   unequal2                ; bytes not equal
          add   eax,8                   ; next 8 bytes
          add   edx,8                   ; next 8 bytes
          or    ch,ch                   ; end of string?
        _until  e                       ; until equal
equal2:
        xor     eax,eax                 ; return 0
    ifndef __STACK__
        pop     ecx                     ; restore registers
    endif
    ifdef _PROFILE
        P5Epilog
    endif
        ret                             ; return

unequal2:
        sbb     eax,eax                 ; eax = 0 if op1>op2, -1 if op1<op2
        or      al,1                    ; eax = 1 if op1>op2, -1 if op1<op2
    ifndef __STACK__
        pop     ecx                     ; restore registers
    endif
    ifdef _PROFILE
        P5Epilog
    endif
        ret                             ; return
        endproc strcmp

        endmod
        end
