From 525ae3f897bf79fd78f3e693bd65056efc8f9109 Mon Sep 17 00:00:00 2001
From: Michael Munday <munday@ca.ibm.com>
Date: Mon, 25 Apr 2016 17:58:34 -0400
Subject: [PATCH] crypto/sha256: add s390x assembly implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Renames block to blockGeneric so that it can be called when the
assembly feature check fails. This means making block a var on
platforms without an assembly implementation (similar to the sha1
package).

Also adds a test to check that the fallback path works correctly
when the feature check fails.

name        old speed      new speed       delta
Hash8Bytes  6.42MB/s ± 1%  27.14MB/s ± 0%  +323.01%  (p=0.000 n=10+10)
Hash1K      53.9MB/s ± 0%  511.1MB/s ± 0%  +847.57%   (p=0.000 n=10+9)
Hash8K      57.1MB/s ± 1%  609.7MB/s ± 0%  +967.04%  (p=0.000 n=10+10)

Change-Id: If962b2a5c9160b3a0b76ccee53b2fd809468ed3d
Reviewed-on: https://go-review.googlesource.com/22460
Run-TryBot: Michael Munday <munday@ca.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bill O'Farrell <billotosyr@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
---
 src/crypto/sha256/fallback_test.go       | 35 ++++++++++++++++++++++++
 src/crypto/sha256/sha256_test.go         | 13 +++++++++
 src/crypto/sha256/sha256block.go         |  4 +--
 src/crypto/sha256/sha256block_decl.go    |  2 +-
 src/crypto/sha256/sha256block_generic.go |  9 ++++++
 src/crypto/sha256/sha256block_s390x.go   | 12 ++++++++
 src/crypto/sha256/sha256block_s390x.s    | 34 +++++++++++++++++++++++
 7 files changed, 105 insertions(+), 4 deletions(-)
 create mode 100644 src/crypto/sha256/fallback_test.go
 create mode 100644 src/crypto/sha256/sha256block_generic.go
 create mode 100644 src/crypto/sha256/sha256block_s390x.go
 create mode 100644 src/crypto/sha256/sha256block_s390x.s

diff --git a/src/crypto/sha256/fallback_test.go b/src/crypto/sha256/fallback_test.go
new file mode 100644
index 00000000000..5917a4862af
--- /dev/null
+++ b/src/crypto/sha256/fallback_test.go
@@ -0,0 +1,35 @@
+// 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 sha256
+
+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 := "e93d84ec2b22383123be9f713697fb25" +
+		"338c86e2f7d8d1ddc2d89d332dd9d76c"
+	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/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go
index 9ac8a96dfce..279cf5ad407 100644
--- a/src/crypto/sha256/sha256_test.go
+++ b/src/crypto/sha256/sha256_test.go
@@ -7,6 +7,7 @@
 package sha256
 
 import (
+	"crypto/rand"
 	"fmt"
 	"io"
 	"testing"
@@ -150,6 +151,18 @@ func TestBlockSize(t *testing.T) {
 	}
 }
 
+// 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
+	rand.Read(buf)
+	blockGeneric(gen, buf)
+	block(asm, buf)
+	if *gen != *asm {
+		t.Error("block and blockGeneric resulted in different states")
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/crypto/sha256/sha256block.go b/src/crypto/sha256/sha256block.go
index ca5efd156a9..d43bbf02453 100644
--- a/src/crypto/sha256/sha256block.go
+++ b/src/crypto/sha256/sha256block.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !386,!amd64
-
 // SHA256 block step.
 // In its own file so that a faster assembly or C version
 // can be substituted easily.
@@ -77,7 +75,7 @@ var _K = []uint32{
 	0xc67178f2,
 }
 
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
 	var w [64]uint32
 	h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
 	for len(p) >= chunk {
diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go
index 35fe34b98a3..e6caff9a746 100644
--- a/src/crypto/sha256/sha256block_decl.go
+++ b/src/crypto/sha256/sha256block_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 386 amd64
+// +build 386 amd64 s390x
 
 package sha256
 
diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go
new file mode 100644
index 00000000000..1a01969b0dc
--- /dev/null
+++ b/src/crypto/sha256/sha256block_generic.go
@@ -0,0 +1,9 @@
+// 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 !amd64,!386,!s390x
+
+package sha256
+
+var block = blockGeneric
diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go
new file mode 100644
index 00000000000..b7beefef0c6
--- /dev/null
+++ b/src/crypto/sha256/sha256block_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 sha256
+
+// featureCheck reports whether the CPU supports the
+// SHA256 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s
new file mode 100644
index 00000000000..ee35991f50c
--- /dev/null
+++ b/src/crypto/sha256/sha256block_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	$0x20, R4      // bit 2 (big endian) for SHA256
+	CMPBEQ	R4, $0, nosha256
+	MOVB	$1, ret+0(FP)
+	RET
+nosha256:
+	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	$2, R0        // SHA256 function code
+loop:
+	WORD	$0xB93E0002   // KIMD R2
+	BVS	loop          // continue if interrupted
+done:
+	XOR	R0, R0        // restore R0
+	RET
+generic:
+	BR	·blockGeneric(SB)
-- 
GitLab