diff options
Diffstat (limited to 'private/crt32/string/alpha/strcmps.s')
-rw-r--r-- | private/crt32/string/alpha/strcmps.s | 357 |
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 |