// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ppc64 || ppc64le // +build ppc64 ppc64le #include "go_asm.h" #include "textflag.h" TEXT ·Compare(SB),NOSPLIT|NOFRAME,$0-56 MOVD a_base+0(FP), R5 MOVD b_base+24(FP), R6 MOVD a_len+8(FP), R3 CMP R5,R6,CR7 MOVD b_len+32(FP), R4 MOVD $ret+48(FP), R7 CMP R3,R4,CR6 BEQ CR7,equal #ifdef GOARCH_ppc64le BR cmpbodyLE<>(SB) #else BR cmpbodyBE<>(SB) #endif equal: BEQ CR6,done MOVD $1, R8 BGT CR6,greater NEG R8 greater: MOVD R8, (R7) RET done: MOVD $0, (R7) RET TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40 MOVD a_base+0(FP), R5 MOVD b_base+16(FP), R6 MOVD a_len+8(FP), R3 CMP R5,R6,CR7 MOVD b_len+24(FP), R4 MOVD $ret+32(FP), R7 CMP R3,R4,CR6 BEQ CR7,equal #ifdef GOARCH_ppc64le BR cmpbodyLE<>(SB) #else BR cmpbodyBE<>(SB) #endif equal: BEQ CR6,done MOVD $1, R8 BGT CR6,greater NEG R8 greater: MOVD R8, (R7) RET done: MOVD $0, (R7) RET // Do an efficient memcmp for ppc64le // R3 = a len // R4 = b len // R5 = a addr // R6 = b addr // R7 = addr of return value TEXT cmpbodyLE<>(SB),NOSPLIT|NOFRAME,$0-0 MOVD R3,R8 // set up length CMP R3,R4,CR2 // unequal? BC 12,8,setuplen // BLT CR2 MOVD R4,R8 // use R4 for comparison len setuplen: MOVD R8,CTR // set up loop counter CMP R8,$8 // only optimize >=8 BLT simplecheck DCBT (R5) // cache hint DCBT (R6) CMP R8,$32 // optimize >= 32 MOVD R8,R9 BLT setup8a // 8 byte moves only setup32a: SRADCC $5,R8,R9 // number of 32 byte chunks MOVD R9,CTR // Special processing for 32 bytes or longer. // Loading this way is faster and correct as long as the // doublewords being compared are equal. Once they // are found unequal, reload them in proper byte order // to determine greater or less than. loop32a: MOVD 0(R5),R9 // doublewords to compare MOVD 0(R6),R10 // get 4 doublewords MOVD 8(R5),R14 MOVD 8(R6),R15 CMPU R9,R10 // bytes equal? MOVD $0,R16 // set up for cmpne BNE cmpne // further compare for LT or GT MOVD 16(R5),R9 // get next pair of doublewords MOVD 16(R6),R10 CMPU R14,R15 // bytes match? MOVD $8,R16 // set up for cmpne BNE cmpne // further compare for LT or GT MOVD 24(R5),R14 // get next pair of doublewords MOVD 24(R6),R15 CMPU R9,R10 // bytes match? MOVD $16,R16 // set up for cmpne BNE cmpne // further compare for LT or GT MOVD $-8,R16 // for cmpne, R5,R6 already inc by 32 ADD $32,R5 // bump up to next 32 ADD $32,R6 CMPU R14,R15 // bytes match? BC 8,2,loop32a // br ctr and cr BNE cmpne ANDCC $24,R8,R9 // Any 8 byte chunks? BEQ leftover // and result is 0 setup8a: SRADCC $3,R9,R9 // get the 8 byte count BEQ leftover // shifted value is 0 MOVD R9,CTR // loop count for doublewords loop8: MOVDBR (R5+R0),R9 // doublewords to compare MOVDBR (R6+R0),R10 // LE compare order ADD $8,R5 ADD $8,R6 CMPU R9,R10 // match? BC 8,2,loop8 // bt ctr <> 0 && cr BGT greater BLT less leftover: ANDCC $7,R8,R9 // check for leftover bytes MOVD R9,CTR // save the ctr BNE simple // leftover bytes BC 12,10,equal // test CR2 for length comparison BC 12,8,less BR greater simplecheck: CMP R8,$0 // remaining compare length 0 BNE simple // do simple compare BC 12,10,equal // test CR2 for length comparison BC 12,8,less // 1st len < 2nd len, result less BR greater // 1st len > 2nd len must be greater simple: MOVBZ 0(R5), R9 // get byte from 1st operand ADD $1,R5 MOVBZ 0(R6), R10 // get byte from 2nd operand ADD $1,R6 CMPU R9, R10 BC 8,2,simple // bc ctr <> 0 && cr BGT greater // 1st > 2nd BLT less // 1st < 2nd BC 12,10,equal // test CR2 for length comparison BC 12,9,greater // 2nd len > 1st len BR less // must be less cmpne: // only here is not equal MOVDBR (R5+R16),R8 // reload in reverse order MOVDBR (R6+R16),R9 CMPU R8,R9 // compare correct endianness BGT greater // here only if NE less: MOVD $-1,R3 MOVD R3,(R7) // return value if A < B RET equal: MOVD $0,(R7) // return value if A == B RET greater: MOVD $1,R3 MOVD R3,(R7) // return value if A > B RET // Do an efficient memcmp for ppc64 (BE) // R3 = a len // R4 = b len // R5 = a addr // R6 = b addr // R7 = addr of return value TEXT cmpbodyBE<>(SB),NOSPLIT|NOFRAME,$0-0 MOVD R3,R8 // set up length CMP R3,R4,CR2 // unequal? BC 12,8,setuplen // BLT CR2 MOVD R4,R8 // use R4 for comparison len setuplen: MOVD R8,CTR // set up loop counter CMP R8,$8 // only optimize >=8 BLT simplecheck DCBT (R5) // cache hint DCBT (R6) CMP R8,$32 // optimize >= 32 MOVD R8,R9 BLT setup8a // 8 byte moves only setup32a: SRADCC $5,R8,R9 // number of 32 byte chunks MOVD R9,CTR loop32a: MOVD 0(R5),R9 // doublewords to compare MOVD 0(R6),R10 // get 4 doublewords MOVD 8(R5),R14 MOVD 8(R6),R15 CMPU R9,R10 // bytes equal? BLT less // found to be less BGT greater // found to be greater MOVD 16(R5),R9 // get next pair of doublewords MOVD 16(R6),R10 CMPU R14,R15 // bytes match? BLT less // found less BGT greater // found greater MOVD 24(R5),R14 // get next pair of doublewords MOVD 24(R6),R15 CMPU R9,R10 // bytes match? BLT less // found to be less BGT greater // found to be greater ADD $32,R5 // bump up to next 32 ADD $32,R6 CMPU R14,R15 // bytes match? BC 8,2,loop32a // br ctr and cr BLT less // with BE, byte ordering is BGT greater // good for compare ANDCC $24,R8,R9 // Any 8 byte chunks? BEQ leftover // and result is 0 setup8a: SRADCC $3,R9,R9 // get the 8 byte count BEQ leftover // shifted value is 0 MOVD R9,CTR // loop count for doublewords loop8: MOVD (R5),R9 MOVD (R6),R10 ADD $8,R5 ADD $8,R6 CMPU R9,R10 // match? BC 8,2,loop8 // bt ctr <> 0 && cr BGT greater BLT less leftover: ANDCC $7,R8,R9 // check for leftover bytes MOVD R9,CTR // save the ctr BNE simple // leftover bytes BC 12,10,equal // test CR2 for length comparison BC 12,8,less BR greater simplecheck: CMP R8,$0 // remaining compare length 0 BNE simple // do simple compare BC 12,10,equal // test CR2 for length comparison BC 12,8,less // 1st len < 2nd len, result less BR greater // same len, must be equal simple: MOVBZ 0(R5),R9 // get byte from 1st operand ADD $1,R5 MOVBZ 0(R6),R10 // get byte from 2nd operand ADD $1,R6 CMPU R9,R10 BC 8,2,simple // bc ctr <> 0 && cr BGT greater // 1st > 2nd BLT less // 1st < 2nd BC 12,10,equal // test CR2 for length comparison BC 12,9,greater // 2nd len > 1st len less: MOVD $-1,R3 MOVD R3,(R7) // return value if A < B RET equal: MOVD $0,(R7) // return value if A == B RET greater: MOVD $1,R3 MOVD R3,(R7) // return value if A > B RET