<commit_before>/*
 * This code is released under the MIT license.
 * For conditions of distribution and use, see the LICENSE or hit the web.
 */
/* SIMD is a rather complicated hash function.
The documentation is fairly extensive, in both theorical and practical terms, with several
implementations provided for reference and speed evaluations.
It is basically made up of two steps. The first is almost embarassingly parallel,
the second is 8-way... what I'm trying to do here is to build up a performance advantage
in the first half so even if the second half gets divergent threads, I still get a gain.

It turns out the amount of divergence is greater than expected so the gain is very diluted,
there are two ways to fix that:
- Move the divergent path out: this would make it embarassingly parallel. I've currently
  written that here as it was written in lib SPH and legacy miners, but it would be much
  more efficient to have it in a proper step, as noted in SIMD documentation.
- Try doing that 8-way (as suggested by documentation). This would solve the divergence
  problem perfectly but I'm going to lose at least one tick in occupancy. */

#define SIMD_REDUCE_BYTE_LUT 0


// A foundamental piece of SIMD architecture used mainly in SIMD16W_MangleInput and in a loop
// beginning what I call the "post-processing" stage.
// In SIMD documentation provided by the Ecole Normale this is a macro REDUCE(x).
// Documentation reads: Reduce modulo 257; result is in [-127; 383]
int SIMD_ByteReduce(int value) {
	return (value & 0x000000FF) - (value >>  8);
}

// Used in reduction loops, called with argument multiplied by alpha.
// See ReductionLoop for more info.
// In SIMD documentation provided by the Ecole Normale this is a macro REDUCE_EXTRA_S(x).
// Documentation reads: Reduce from [-127; 383] to [-128; 128]
int SIMD_ShortReduce(int value) {
	return (value & 0x0000FFFF) + (value >> 16);
}


// This is called "FFT8" in legacy kernels. The implementation is very similar to legacy.
// I just fetch directly from memory (instead of regs) and write to LDS (instead of other regs).
int8 SIMD16W_MangleInput(global uchar *input, uint offset) {
	int x[4];
	for(uint loop = 0; loop < 4; loop++) {
		x[loop] = offset < 64? input[offset] : 0; // select is inlined for scalars
		offset += 32;
	}	
	int a[4];
	for(uint loop = 0; loop < 2; loop++) {
		int mul = loop % 1? -1 : 1;
		int shft = x[2] << 4;
		a[loop * 2 + 0] = x[0] + x[2] * mul;
		a[loop * 2 + 1] = x[0] + shft * mul;
	}
	int b[4];
	b[0] = x[1] + x[3];
	b[2] = (x[1] << 4) - (x[3] << 4);
#if SIMD_REDUCE_BYTE_LUT == 0
	b[1] = SIMD_ByteReduce((x[1] << 2) + (x[3] << 6));
	b[3] = SIMD_ByteReduce((x[1] << 6) + (x[3] << 2));
	/* Values here have special properties. Guaranteed to be [0..255] and
	very likely being (0, u) or even (0, 0). Therefore very high coherence with
	late values having the same value. I cannot risk bank collisions here, use L1 instead. */
#else
#if !defined(SIMD_REDUCE_BYTE_LUT) || SIMD_REDUCE_BYTE_LUT > 1
	b[1] = reduced[x[1] * 256 + x[3]];	
#else
	b[1] = SIMD_ByteReduce((x[1] << 2) + (x[3] << 6));
#endif
	b[3] = reduced[x[3] * 256 + x[1]];	
#endif
	return (int8)(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3],
	              a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]);
}


// Define LDS layout. Never delete this, it is nice at least for documentation purposes.
// Even though we use this, it is called relatively sparingly and then we work on relative movements.
// Therefore stuff will break very likely if this is changed.
uint LDSIDX(uint column, uint slot, uint hashIndex) {
	uint general = column + (hashIndex % 2? 16 : 0); // odd hashes right half of LDS banks
	general += slot * 32; // LDS line length in 4byte words, state is stored "rotated"
	return general + (hashIndex / 2? 32 * 16 : 0);
}

// linear index in canonical w state --> LDS offset in real work array
uint LDSLINEAR(uint i) {
	uint col = i / 16;
	uint slot = i % 16;<commit_msg>BUG in SIMD Get the rid of an useless mul<commit_after>/*
 * This code is released under the MIT license.
 * For conditions of distribution and use, see the LICENSE or hit the web.
 */
/* SIMD is a rather complicated hash function.
The documentation is fairly extensive, in both theorical and practical terms, with several
implementations provided for reference and speed evaluations.
It is basically made up of two steps. The first is almost embarassingly parallel,
the second is 8-way... what I'm trying to do here is to build up a performance advantage
in the first half so even if the second half gets divergent threads, I still get a gain.

It turns out the amount of divergence is greater than expected so the gain is very diluted,
there are two ways to fix that:
- Move the divergent path out: this would make it embarassingly parallel. I've currently
  written that here as it was written in lib SPH and legacy miners, but it would be much
  more efficient to have it in a proper step, as noted in SIMD documentation.
- Try doing that 8-way (as suggested by documentation). This would solve the divergence
  problem perfectly but I'm going to lose at least one tick in occupancy. */

#define SIMD_REDUCE_BYTE_LUT 0


// A foundamental piece of SIMD architecture used mainly in SIMD16W_MangleInput and in a loop
// beginning what I call the "post-processing" stage.
// In SIMD documentation provided by the Ecole Normale this is a macro REDUCE(x).
// Documentation reads: Reduce modulo 257; result is in [-127; 383]
int SIMD_ByteReduce(int value) {
	return (value & 0x000000FF) - (value >>  8);
}

// Used in reduction loops, called with argument multiplied by alpha.
// See ReductionLoop for more info.
// In SIMD documentation provided by the Ecole Normale this is a macro REDUCE_EXTRA_S(x).
// Documentation reads: Reduce from [-127; 383] to [-128; 128]
int SIMD_ShortReduce(int value) {
	return (value & 0x0000FFFF) + (value >> 16);
}


// This is called "FFT8" in legacy kernels. The implementation is very similar to legacy.
// I just fetch directly from memory (instead of regs) and write to LDS (instead of other regs).
int8 SIMD16W_MangleInput(global uchar *input, uint offset) {
	int x[4];
	for(uint loop = 0; loop < 4; loop++) {
		x[loop] = offset < 64? input[offset] : 0; // select is inlined for scalars
		offset += 32;
	}	
	int a[4];
	for(uint loop = 0; loop < 2; loop++) {
		a[loop * 2 + 0] = x[0] + x[2];
		a[loop * 2 + 1] = x[0] + x[2] << 4;
	}
	int b[4];
	b[0] = x[1] + x[3];
	b[2] = (x[1] << 4) - (x[3] << 4);
#if !defined(SIMD_REDUCE_BYTE_LUT) || SIMD_REDUCE_BYTE_LUT == 0
	b[1] = SIMD_ByteReduce((x[1] << 2) + (x[3] << 6));
	b[3] = SIMD_ByteReduce((x[1] << 6) + (x[3] << 2));
	/* Values here have special properties. Guaranteed to be [0..255] and
	very likely being (0, u) or even (0, 0). Therefore very high coherence with
	late values having the same value. I cannot risk bank collisions here, use L1 instead. */
#else
#if SIMD_REDUCE_BYTE_LUT > 1
	b[1] = reduced[x[1] * 256 + x[3]];	
#else
	b[1] = SIMD_ByteReduce((x[1] << 2) + (x[3] << 6));
#endif
	b[3] = reduced[x[3] * 256 + x[1]];	
#endif
	return (int8)(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3],
	              a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]);
}


// Define LDS layout. Never delete this, it is nice at least for documentation purposes.
// Even though we use this, it is called relatively sparingly and then we work on relative movements.
// Therefore stuff will break very likely if this is changed.
uint LDSIDX(uint column, uint slot, uint hashIndex) {
	uint general = column + (hashIndex % 2? 16 : 0); // odd hashes right half of LDS banks
	general += slot * 32; // LDS line length in 4byte words, state is stored "rotated"
	return general + (hashIndex / 2? 32 * 16 : 0);
}

// linear index in canonical w state --> LDS offset in real work array
uint LDSLINEAR(uint i) {
	uint col = i / 16;
	uint slot = i % 16;
{'fraction_non_alphanumeric': 0.11608161196299582, 'fraction_numerical': 0.037130908630084905, 'mean_word_length': 3.583042973286876, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4190723', 'n_tokens_mistral': 2876, 'n_tokens_neox': 2591, 'n_words': 1169}