/*
 * Load-instrumented copy of the FIXED memcchr (fix.diff applied to
 * sys/libkern/memcchr.c).  Same instrumentation as memcchr_instr.c.
 * Expectation: g_below_start == g_past_end == g_outside_granule == 0
 * (every load fully in range) while the differential vs the naive
 * reference stays at zero failures.
 */
#include "prelude.h"

#define	LONGPTR_MASK (sizeof(long) - 1)

unsigned long g_below_start, g_past_end, g_in;
unsigned long g_max_below, g_max_past;
unsigned long g_filtered;
unsigned long g_outside_granule;
const unsigned char *g_lo, *g_hi;

#define NOTE(p, sz) do {                                                    \
    const unsigned char *_p = (const unsigned char *)(p);                   \
    if (_p < g_lo) {                                                        \
        g_below_start++;                                                    \
        { unsigned long _d = (unsigned long)(g_lo - _p);                    \
          if (_d > g_max_below) g_max_below = _d; }                         \
    } else if (_p + (sz) > g_hi) {                                          \
        g_past_end++;                                                       \
        { unsigned long _d = (unsigned long)(_p + (sz) - g_hi);             \
          if (_d > g_max_past) g_max_past = _d; }                           \
    } else g_in++;                                                          \
    if (_p < (const unsigned char *)((uintptr_t)g_lo & ~(uintptr_t)7) ||    \
        _p + (sz) >                                                         \
        (const unsigned char *)(((uintptr_t)g_hi + 7) & ~(uintptr_t)7))     \
        g_outside_granule++;                                                \
} while (0)

#define LDC(e) ({ const unsigned long *_q = (e);                               \
    NOTE((const unsigned char *)_q, sizeof(unsigned long)); *_q; })
#define LDB(e) ({ const unsigned char *_q = (e); NOTE(_q, 1); *_q; })

static int g_c;
#define TESTBYTE_I                              \
	do {                                        \
		if (LDB(p) != (unsigned char)g_c)       \
			goto done;                          \
		p++;                                    \
	} while (0)

void *
memcchr_fixed_instr(const void *begin, int c, size_t n)
{
	const unsigned long *lp;
	const unsigned char *p, *end;
	unsigned long word;

	g_c = c;
	g_lo = (const unsigned char *)begin;
	g_hi = (const unsigned char *)begin + n;

	/* Four or eight repetitions of `c'. */
	word = (unsigned char)c;
	word |= word << 8;
	word |= word << 16;
#if LONG_BIT >= 64
	word |= word << 32;
#endif

	/* Don't perform memory I/O when passing a zero-length buffer. */
	if (n == 0)
		return (NULL);

	end = (const unsigned char *)begin + n;

	/* Compare bytewise until word aligned: no loads below begin. */
	for (p = begin; p < end && ((uintptr_t)p & LONGPTR_MASK);)
		TESTBYTE_I;

	/* Compare one word at a time while the whole word is in range. */
	for (lp = (const unsigned long *)p;
	    (const unsigned char *)(lp + 1) <= end; lp++) {
		unsigned long w = LDC(lp);
		if (w != word) {
			p = (const unsigned char *)lp;
			TESTBYTE_I;
			TESTBYTE_I;
			TESTBYTE_I;
#if LONG_BIT >= 64
			TESTBYTE_I;
			TESTBYTE_I;
			TESTBYTE_I;
			TESTBYTE_I;
#endif
			goto done;
		}
	}

	/* Trailing bytes: no loads past end. */
	for (p = (const unsigned char *)lp; p < end;)
		TESTBYTE_I;

	return (NULL);

done:
	if (p >= end)
		g_filtered++;
	if (p < end)
		return (__DECONST(void *, p));
	return (NULL);
}
