summaryrefslogtreecommitdiffstats
path: root/private/crt32/string/alpha/strcmps.s
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/string/alpha/strcmps.s')
-rw-r--r--private/crt32/string/alpha/strcmps.s357
1 files changed, 357 insertions, 0 deletions
diff --git a/private/crt32/string/alpha/strcmps.s b/private/crt32/string/alpha/strcmps.s
new file mode 100644
index 000000000..0c7859727
--- /dev/null
+++ b/private/crt32/string/alpha/strcmps.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().
+ #
+ # 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