mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
9.7 KiB
357 lines
9.7 KiB
#****************************************************************************
|
|
#* *
|
|
#* 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().
|
|
#
|
|
# 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 strcmp
|
|
.ent strcmp
|
|
|
|
# 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
|
|
#
|
|
|
|
strcmp:
|
|
.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 strcmp
|