#**************************************************************************** #* * #* 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 A0 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 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 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 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 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