From 90826b1ac2ae7b69f0f1816e0354198ea9836796 Mon Sep 17 00:00:00 2001
From: mancoast <RobertPancoast77@gmail.com>
Date: Thu, 18 Aug 2016 17:24:06 -0400
Subject: [PATCH 1/7] Critical Section __m512i union

This improves performance using 512bit SIMD instructions.
---
 src/libethash/internal.c | 44 ++++++++++++++++++++++++++++++++++++++++
 src/libethash/internal.h |  4 ++++
 2 files changed, 48 insertions(+)

diff --git a/src/libethash/internal.c b/src/libethash/internal.c
index 0a830fc8..8a34d3c9 100644
--- a/src/libethash/internal.c
+++ b/src/libethash/internal.c
@@ -108,6 +108,9 @@ void ethash_calculate_dag_item(
 	__m128i xmm1 = ret->xmm[1];
 	__m128i xmm2 = ret->xmm[2];
 	__m128i xmm3 = ret->xmm[3];
+#elif defined(__MIC__)
+	__m512i const fnv_prime = _mm512_set1_epi32(FNV_PRIME);
+	__m512i zmm0 = ret->zmm[0];
 #endif
 
 	for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
@@ -131,6 +134,14 @@ void ethash_calculate_dag_item(
 			ret->xmm[2] = xmm2;
 			ret->xmm[3] = xmm3;
 		}
+		#elif defined(__MIC__)
+		{
+			zmm0 = _mm512_mullo_epi32(zmm0, fnv_prime);
+
+			// have to write to ret as values are used to compute index
+			zmm0 = _mm512_xor_si512(zmm0, parent->zmm[0]);
+			ret->zmm[0] = zmm0;
+		}
 		#else
 		{
 			for (unsigned w = 0; w != NODE_WORDS; ++w) {
@@ -227,6 +238,14 @@ static bool ethash_hash(
 				mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]);
 				mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]);
 			}
+			#elif defined(__MIC__)
+			{
+				// __m512i implementation via union
+				//	Each vector register (zmm) can store sixteen 32-bit integer numbers
+				__m512i fnv_prime = _mm512_set1_epi32(FNV_PRIME);
+				__m512i zmm0 = _mm512_mullo_epi32(fnv_prime, mix[n].zmm[0]);
+				mix[n].zmm[0] = _mm512_xor_si512(zmm0, dag_node->zmm[0]);
+			}
 			#else
 			{
 				for (unsigned w = 0; w != NODE_WORDS; ++w) {
@@ -300,7 +319,11 @@ ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t cons
 	if (!ret) {
 		return NULL;
 	}
+#if defined(__MIC__)
+	ret->cache = _mm_malloc((size_t)cache_size, 64);
+#else
 	ret->cache = malloc((size_t)cache_size);
+#endif
 	if (!ret->cache) {
 		goto fail_free_light;
 	}
@@ -312,7 +335,11 @@ ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t cons
 	return ret;
 
 fail_free_cache_mem:
+#if defined(__MIC__)
+	_mm_free(ret->cache);
+#else
 	free(ret->cache);
+#endif
 fail_free_light:
 	free(ret);
 	return NULL;
@@ -408,6 +435,17 @@ ethash_full_t ethash_full_new_internal(
 			ETHASH_CRITICAL("mmap failure()");
 			goto fail_close_file;
 		}
+#if defined(__MIC__)
+		node* tmp_nodes = _mm_malloc((size_t)full_size, 64);
+		//copy all nodes from ret->data
+		//mmapped_nodes are not aligned properly
+		uint32_t const countnodes = (uint32_t) ((size_t)ret->file_size / sizeof(node));
+		//fprintf(stderr,"ethash_full_new_internal:countnodes:%d",countnodes);
+		for (uint32_t i = 1; i != countnodes; ++i) {
+			tmp_nodes[i] = ret->data[i];
+		}
+		ret->data = tmp_nodes;
+#endif
 		return ret;
 	case ETHASH_IO_MEMO_SIZE_MISMATCH:
 		// if a DAG of same filename but unexpected size is found, silently force new file creation
@@ -424,6 +462,9 @@ ethash_full_t ethash_full_new_internal(
 		break;
 	}
 
+#if defined(__MIC__)
+	ret->data = _mm_malloc((size_t)full_size, 64);
+#endif
 	if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
 		ETHASH_CRITICAL("Failure at computing DAG data.");
 		goto fail_free_full_data;
@@ -448,6 +489,9 @@ ethash_full_t ethash_full_new_internal(
 fail_free_full_data:
 	// could check that munmap(..) == 0 but even if it did not can't really do anything here
 	munmap(ret->data, (size_t)full_size);
+#if defined(__MIC__)
+	_mm_free(ret->data);
+#endif
 fail_close_file:
 	fclose(ret->file);
 fail_free_full:
diff --git a/src/libethash/internal.h b/src/libethash/internal.h
index 26c395ad..35419c6a 100644
--- a/src/libethash/internal.h
+++ b/src/libethash/internal.h
@@ -8,6 +8,8 @@
 
 #if defined(_M_X64) && ENABLE_SSE
 #include <smmintrin.h>
+#elif defined(__MIC__)
+#include <immintrin.h>
 #endif
 
 #ifdef __cplusplus
@@ -27,6 +29,8 @@ typedef union node {
 
 #if defined(_M_X64) && ENABLE_SSE
 	__m128i xmm[NODE_WORDS/4];
+#elif defined(__MIC__)
+	__m512i zmm[NODE_WORDS/16];
 #endif
 
 } node;

From 0e2f2ec9d460ae868dd1c04cdc60f9031fc01615 Mon Sep 17 00:00:00 2001
From: Neil Moore <dar13.dev@gmail.com>
Date: Thu, 8 Jun 2017 21:34:33 -0400
Subject: [PATCH 2/7] Resolve GCC 7+ warnings

Fixes #4115.
---
 src/libethash/internal.c | 52 +++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 25 deletions(-)

diff --git a/src/libethash/internal.c b/src/libethash/internal.c
index 8a34d3c9..0d8f12fc 100644
--- a/src/libethash/internal.c
+++ b/src/libethash/internal.c
@@ -218,10 +218,10 @@ static bool ethash_hash(
 
 		for (unsigned n = 0; n != MIX_NODES; ++n) {
 			node const* dag_node;
+			node tmp_node;
 			if (full_nodes) {
 				dag_node = &full_nodes[MIX_NODES * index + n];
 			} else {
-				node tmp_node;
 				ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light);
 				dag_node = &tmp_node;
 			}
@@ -426,42 +426,44 @@ ethash_full_t ethash_full_new_internal(
 		return NULL;
 	}
 	ret->file_size = (size_t)full_size;
-	switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
-	case ETHASH_IO_FAIL:
-		// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
+
+	enum ethash_io_rc err = ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false);
+	if (err == ETHASH_IO_FAIL)
 		goto fail_free_full;
-	case ETHASH_IO_MEMO_MATCH:
-		if (!ethash_mmap(ret, f)) {
-			ETHASH_CRITICAL("mmap failure()");
-			goto fail_close_file;
-		}
-#if defined(__MIC__)
-		node* tmp_nodes = _mm_malloc((size_t)full_size, 64);
-		//copy all nodes from ret->data
-		//mmapped_nodes are not aligned properly
-		uint32_t const countnodes = (uint32_t) ((size_t)ret->file_size / sizeof(node));
-		//fprintf(stderr,"ethash_full_new_internal:countnodes:%d",countnodes);
-		for (uint32_t i = 1; i != countnodes; ++i) {
-			tmp_nodes[i] = ret->data[i];
-		}
-		ret->data = tmp_nodes;
-#endif
-		return ret;
-	case ETHASH_IO_MEMO_SIZE_MISMATCH:
+
+	if (err == ETHASH_IO_MEMO_SIZE_MISMATCH) {
 		// if a DAG of same filename but unexpected size is found, silently force new file creation
 		if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
 			ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
 			goto fail_free_full;
 		}
-		// fallthrough to the mismatch case here, DO NOT go through match
-	case ETHASH_IO_MEMO_MISMATCH:
+		// we now need to go through the mismatch case, NOT the match case
+		err = ETHASH_IO_MEMO_MISMATCH;
+	}
+
+	if (err == ETHASH_IO_MEMO_MISMATCH || err == ETHASH_IO_MEMO_MATCH) {
 		if (!ethash_mmap(ret, f)) {
 			ETHASH_CRITICAL("mmap failure()");
 			goto fail_close_file;
 		}
-		break;
+
+		if (err == ETHASH_IO_MEMO_MATCH) {
+#if defined(__MIC__)
+			node* tmp_nodes = _mm_malloc((size_t)full_size, 64);
+			//copy all nodes from ret->data
+			//mmapped_nodes are not aligned properly
+			uint32_t const countnodes = (uint32_t) ((size_t)ret->file_size / sizeof(node));
+			//fprintf(stderr,"ethash_full_new_internal:countnodes:%d",countnodes);
+			for (uint32_t i = 1; i != countnodes; ++i) {
+				tmp_nodes[i] = ret->data[i];
+			}
+			ret->data = tmp_nodes;
+#endif
+			return ret;
+		}
 	}
 
+
 #if defined(__MIC__)
 	ret->data = _mm_malloc((size_t)full_size, 64);
 #endif

From 2e05a27aa276c9d09d456ca521e89e32cad31790 Mon Sep 17 00:00:00 2001
From: Andrei Maiboroda <andrei@ethereum.org>
Date: Wed, 29 Mar 2017 14:24:38 +0200
Subject: [PATCH 3/7] Use 64-bit seek functions instead of fseek when
 generating DAG file

---
 src/libethash/io.c       |  2 +-
 src/libethash/io.h       | 10 ++++++++++
 src/libethash/io_posix.c |  5 +++++
 src/libethash/io_win32.c |  6 ++++++
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/libethash/io.c b/src/libethash/io.c
index f4db477c..ffb1a0e7 100644
--- a/src/libethash/io.c
+++ b/src/libethash/io.c
@@ -91,7 +91,7 @@ enum ethash_io_rc ethash_io_prepare(
 		goto free_memo;
 	}
 	// make sure it's of the proper size
-	if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
+	if (ethash_fseek(f, file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1, SEEK_SET) != 0) {
 		fclose(f);
 		ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
 		goto free_memo;
diff --git a/src/libethash/io.h b/src/libethash/io.h
index 7a27089c..06bd8c3b 100644
--- a/src/libethash/io.h
+++ b/src/libethash/io.h
@@ -113,6 +113,16 @@ enum ethash_io_rc ethash_io_prepare(
  */
 FILE* ethash_fopen(char const* file_name, char const* mode);
 
+/**
+ * An fseek wrapper for crossplatform 64-bit seek.
+ *
+ * @param f            The file stream whose fd to get
+ * @param offset       Number of bytes from @a origin
+ * @param origin       Initial position
+ * @return             Current offset or -1 to indicate an error
+ */
+int ethash_fseek(FILE* f, size_t offset, int origin);
+
 /**
  * An strncat wrapper for no-warnings crossplatform strncat.
  *
diff --git a/src/libethash/io_posix.c b/src/libethash/io_posix.c
index c9a17d84..be8e6542 100644
--- a/src/libethash/io_posix.c
+++ b/src/libethash/io_posix.c
@@ -34,6 +34,11 @@ FILE* ethash_fopen(char const* file_name, char const* mode)
 	return fopen(file_name, mode);
 }
 
+int ethash_fseek(FILE* f, size_t offset, int origin)
+{
+	return fseeko(f, offset, origin);
+}
+
 char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
 {
 	return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
diff --git a/src/libethash/io_win32.c b/src/libethash/io_win32.c
index 34f1aaa7..2fb0e6c9 100644
--- a/src/libethash/io_win32.c
+++ b/src/libethash/io_win32.c
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <shlobj.h>
+#include <io.h>
 
 FILE* ethash_fopen(char const* file_name, char const* mode)
 {
@@ -33,6 +34,11 @@ FILE* ethash_fopen(char const* file_name, char const* mode)
 	return fopen_s(&f, file_name, mode) == 0 ? f : NULL;
 }
 
+int ethash_fseek(FILE* f, size_t offset, int origin)
+{
+	return _fseeki64(f, offset, origin);
+}
+
 char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
 {
 	return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL;

From 7310406afae193fea51a7f5b546809b99a19e4b2 Mon Sep 17 00:00:00 2001
From: Bob Summerwill <bob@summerwill.net>
Date: Sun, 12 Jun 2016 21:20:06 -0700
Subject: [PATCH 4/7] Added warning suppression using pragmas for Debian. It
 looks like older versions of GCC have slightly unreliable logic for array
 out-of-bounds detection. Code in ethash which uses unions and arrays is
 firing a warning in both Debian Jesse (8.5) and in the ARM Linux
 cross-builds. Debian Jesse uses GCC 4.9.2.   The cross-builds are using GCC
 4.8.4. Other distros are using GCC 5.x or even GCC 6.x (Arch). The issue is
 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273 and was fixed in GCC 5.0
 and backported to 4.9.3.

Updated comments.
---
 src/libethash/internal.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/libethash/internal.c b/src/libethash/internal.c
index 0d8f12fc..618238bd 100644
--- a/src/libethash/internal.c
+++ b/src/libethash/internal.c
@@ -257,6 +257,22 @@ static bool ethash_hash(
 
 	}
 
+// Workaround for a GCC regression which causes a bogus -Warray-bounds warning.
+// The regression was introduced in GCC 4.8.4, fixed in GCC 5.0.0 and backported to GCC 4.9.3 but
+// never to the GCC 4.8.x line.
+//
+// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273
+//
+// This regression is affecting Debian Jesse (8.5) builds of cpp-ethereum (GCC 4.9.2) and also
+// manifests in the doublethinkco armel v5 cross-builds, which use crosstool-ng and resulting
+// in the use of GCC 4.8.4.  The Tizen runtime wants an even older GLIBC version - the one from
+// GCC 4.6.0!
+
+#if defined(__GNUC__) && (__GNUC__ < 5)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif // define (__GNUC__)
+
 	// compress mix
 	for (uint32_t w = 0; w != MIX_WORDS; w += 4) {
 		uint32_t reduction = mix->words[w + 0];
@@ -266,6 +282,10 @@ static bool ethash_hash(
 		mix->words[w / 4] = reduction;
 	}
 
+#if defined(__GNUC__) && (__GNUC__ < 5)
+#pragma GCC diagnostic pop
+#endif // define (__GNUC__)
+
 	fix_endian_arr32(mix->words, MIX_WORDS / 4);
 	memcpy(&ret->mix_hash, mix->bytes, 32);
 	// final Keccak hash

From 31fbca2ef83b7219eba7cf0026ba9f292a54f360 Mon Sep 17 00:00:00 2001
From: Bob Summerwill <bob@summerwill.net>
Date: Mon, 9 May 2016 11:41:39 -0700
Subject: [PATCH 5/7] Fix GCC warning - 'static' is not at beginning of
 declaration. With this change we will be able to remove a global warning
 suppression from our CMake files.

---
 src/libethash/internal.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libethash/internal.c b/src/libethash/internal.c
index 618238bd..0e69f009 100644
--- a/src/libethash/internal.c
+++ b/src/libethash/internal.c
@@ -56,7 +56,7 @@ uint64_t ethash_get_cachesize(uint64_t const block_number)
 // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
 // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
 // SeqMemoHash(s, R, N)
-bool static ethash_compute_cache_nodes(
+static bool ethash_compute_cache_nodes(
 	node* const nodes,
 	uint64_t cache_size,
 	ethash_h256_t const* seed

From 03d18d67ae6b259fb9b40871779575345c7bd0a4 Mon Sep 17 00:00:00 2001
From: Yoichi Hirai <i@yoichihirai.com>
Date: Thu, 1 Dec 2016 19:05:28 +0100
Subject: [PATCH 6/7] libethash: avoid passing nullptr to strlen

---
 src/libethash/io_posix.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libethash/io_posix.c b/src/libethash/io_posix.c
index be8e6542..b831acf1 100644
--- a/src/libethash/io_posix.c
+++ b/src/libethash/io_posix.c
@@ -101,6 +101,8 @@ bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
 		struct passwd* pwd = getpwuid(getuid());
 		if (pwd)
 			home_dir = pwd->pw_dir;
+		if (!home_dir)
+			return false;
 	}
 	
 	size_t len = strlen(home_dir);

From 04efce18196c952d50c1db110a81227503b88aea Mon Sep 17 00:00:00 2001
From: hackyminer <hackyminer@gmail.com>
Date: Sun, 25 Nov 2018 07:56:58 +0900
Subject: [PATCH 7/7] add a missing blockNum parameter

---
 ethash.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ethash.go b/ethash.go
index 21c10c87..837a16c1 100644
--- a/ethash.go
+++ b/ethash.go
@@ -130,7 +130,7 @@ func (l *Light) Verify(block Block) bool {
 	// to prevent DOS attacks.
 	blockNum := block.NumberU64()
 	if blockNum >= epochLength*2048 {
-		log.Debug(fmt.Sprintf("block number %d too high, limit is %d", epochLength*2048))
+		log.Debug(fmt.Sprintf("block number %d too high, limit is %d", blockNum, epochLength*2048))
 		return false
 	}