From 63ceeafa308b99e6b7d5480521b83360b4f6b2fd Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Mon, 18 Apr 2016 17:41:50 -0400 Subject: [PATCH] crypto/sha1: add s390x assembly implementation Use the compute intermediate message digest (KIMD) instruction when possible. Adds test to check fallback code path in case KIMD is not available. Benchmark changes: Hash8Bytes 3.4x Hash1K 9.3x Hash8K 10.9x Change-Id: Ibcd71a886dfd7b3822042235b4f4eaa7a148036b Reviewed-on: https://go-review.googlesource.com/22350 Run-TryBot: Michael Munday TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/crypto/sha1/fallback_test.go | 34 ++++++++++++++++++++++++++++ src/crypto/sha1/sha1_test.go | 2 +- src/crypto/sha1/sha1block_decl.go | 2 +- src/crypto/sha1/sha1block_generic.go | 2 +- src/crypto/sha1/sha1block_s390x.go | 12 ++++++++++ src/crypto/sha1/sha1block_s390x.s | 34 ++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 src/crypto/sha1/fallback_test.go create mode 100644 src/crypto/sha1/sha1block_s390x.go create mode 100644 src/crypto/sha1/sha1block_s390x.s diff --git a/src/crypto/sha1/fallback_test.go b/src/crypto/sha1/fallback_test.go new file mode 100644 index 0000000000..08acd044d0 --- /dev/null +++ b/src/crypto/sha1/fallback_test.go @@ -0,0 +1,34 @@ +// Copyright 2016 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. + +// +build s390x + +package sha1 + +import ( + "fmt" + "io" + "testing" +) + +// Tests the fallback code path in case the optimized asm +// implementation cannot be used. +// See also TestBlockGeneric. +func TestGenericPath(t *testing.T) { + if useAsm == false { + t.Skipf("assembly implementation unavailable") + } + useAsm = false + defer func() { useAsm = true }() + c := New() + in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ" + gold := "0f58c2bb130f8182375f325c18342215255387e5" + if _, err := io.WriteString(c, in); err != nil { + t.Fatalf("could not write to c: %v", err) + } + out := fmt.Sprintf("%x", c.Sum(nil)) + if out != gold { + t.Fatalf("mismatch: got %s, wanted %s", out, gold) + } +} diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go index 80ac5e9f74..9202e682a8 100644 --- a/src/crypto/sha1/sha1_test.go +++ b/src/crypto/sha1/sha1_test.go @@ -91,7 +91,7 @@ func TestBlockSize(t *testing.T) { } } -// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match. +// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match. func TestBlockGeneric(t *testing.T) { gen, asm := New().(*digest), New().(*digest) buf := make([]byte, BlockSize*20) // arbitrary factor diff --git a/src/crypto/sha1/sha1block_decl.go b/src/crypto/sha1/sha1block_decl.go index 082735f064..a85b74b878 100644 --- a/src/crypto/sha1/sha1block_decl.go +++ b/src/crypto/sha1/sha1block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 amd64p32 arm 386 +// +build amd64 amd64p32 arm 386 s390x package sha1 diff --git a/src/crypto/sha1/sha1block_generic.go b/src/crypto/sha1/sha1block_generic.go index 696e26b625..f0194626a6 100644 --- a/src/crypto/sha1/sha1block_generic.go +++ b/src/crypto/sha1/sha1block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!amd64p32,!386,!arm +// +build !amd64,!amd64p32,!386,!arm,!s390x package sha1 diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go new file mode 100644 index 0000000000..aac7c1182d --- /dev/null +++ b/src/crypto/sha1/sha1block_s390x.go @@ -0,0 +1,12 @@ +// Copyright 2016 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. + +package sha1 + +// featureCheck reports whether the CPU supports the +// SHA1 compute intermediate message digest (KIMD) +// function code. +func featureCheck() bool + +var useAsm = featureCheck() diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s new file mode 100644 index 0000000000..a9c4b085ed --- /dev/null +++ b/src/crypto/sha1/sha1block_s390x.s @@ -0,0 +1,34 @@ +// Copyright 2016 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. + +#include "textflag.h" + +// func featureCheck() bool +TEXT ·featureCheck(SB),NOSPLIT,$16-1 + LA tmp-16(SP), R1 + XOR R0, R0 // query function code is 0 + WORD $0xB93E0006 // KIMD (R6 is ignored) + MOVBZ tmp-16(SP), R4 // get the first byte + AND $0x40, R4 // bit 1 (big endian) for SHA1 + CMPBEQ R4, $0, nosha1 + MOVB $1, ret+0(FP) + RET +nosha1: + MOVB $0, ret+0(FP) + RET + +// func block(dig *digest, p []byte) +TEXT ·block(SB),NOSPLIT,$0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + CMPBNE R4, $1, generic + MOVBZ $1, R0 // SHA1 function code +loop: + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted +done: + XOR R0, R0 // restore R0 + RET +generic: + BR ·blockGeneric(SB) -- 2.48.1