Perl_fbm_instr(pTHX_ unsigned char *big, unsigned char *bigend, SV *littlestr, U32 flags)
{
    unsigned char *s;
    STRLEN l;
    const unsigned char *little = (const unsigned char *)SvPV_const(littlestr,l);
    STRLEN littlelen = l;
    const I32 multiline = flags & FBMrf_MULTILINE;
    bool valid = SvVALID(littlestr);
    bool tail = valid ? cBOOL(SvTAIL(littlestr)) : FALSE;

    PERL_ARGS_ASSERT_FBM_INSTR;

    assert(bigend >= big);

    if ((STRLEN)(bigend - big) < littlelen) {
	if (     tail
	     && ((STRLEN)(bigend - big) == littlelen - 1)
	     && (littlelen == 1
		 || (*big == *little &&
		     memEQ((char *)big, (char *)little, littlelen - 1))))
	    return (char*)big;
	return NULL;
    }

    switch (littlelen) { /* Special cases for 0, 1 and 2  */
    case 0:
	return (char*)big;		/* Cannot be SvTAIL! */

    case 1:
	    if (tail && !multiline) /* Anchor only! */
		/* [-1] is safe because we know that bigend != big.  */
		return (char *) (bigend - (bigend[-1] == '\n'));

	    s = (unsigned char *)memchr((void*)big, *little, bigend-big);
            if (s)
                return (char *)s;
	    if (tail)
		return (char *) bigend;
	    return NULL;

    case 2:
	if (tail && !multiline) {
            /* a littlestr with SvTAIL must be of the form "X\n" (where X
             * is a single char). It is anchored, and can only match
             * "....X\n"  or  "....X" */
            if (bigend[-2] == *little && bigend[-1] == '\n')
		return (char*)bigend - 2;
	    if (bigend[-1] == *little)
		return (char*)bigend - 1;
	    return NULL;
	}

	{
            /* memchr() is likely to be very fast, possibly using whatever
             * hardware support is available, such as checking a whole
             * cache line in one instruction.
             * So for a 2 char pattern, calling memchr() is likely to be
             * faster than running FBM, or rolling our own. The previous
             * version of this code was roll-your-own which typically
             * only needed to read every 2nd char, which was good back in
             * the day, but no longer.
             */
	    unsigned char c1 = little[0];
	    unsigned char c2 = little[1];

            /* *** for all this case, bigend points to the last char,
             * not the trailing \0: this makes the conditions slightly
             * simpler */
            bigend--;
	    s = big;
            if (c1 != c2) {
                while (s < bigend) {
                    /* do a quick test for c1 before calling memchr();
                     * this avoids the expensive fn call overhead when
                     * there are lots of c1's */
                    if (LIKELY(*s != c1)) {
                        s++;
                        s = (unsigned char *)memchr((void*)s, c1, bigend - s);
                        if (!s)
                            break;
                    }
                    if (s[1] == c2)
                        return (char*)s;

                    /* failed; try searching for c2 this time; that way
                     * we don't go pathologically slow when the string
                     * consists mostly of c1's or vice versa.
                     */
                    s += 2;
                    if (s > bigend)
                        break;
                    s = (unsigned char *)memchr((void*)s, c2, bigend - s + 1);
                    if (!s)
                        break;
                    if (s[-1] == c1)
                        return (char*)s - 1;
                }
            }
            else {
                /* c1, c2 the same */
                while (s < bigend) {
                    if (s[0] == c1) {
                      got_1char:
                        if (s[1] == c1)
                            return (char*)s;
                        s += 2;
                    }
                    else {
                        s++;
                        s = (unsigned char *)memchr((void*)s, c1, bigend - s);
                        if (!s || s >= bigend)
                            break;
                        goto got_1char;
                    }
                }
            }

            /* failed to find 2 chars; try anchored match at end without
             * the \n */
            if (tail && bigend[0] == little[0])
                return (char *)bigend;
            return NULL;
        }

    default:
	break; /* Only lengths 0 1 and 2 have special-case code.  */
    }

    if (tail && !multiline) {	/* tail anchored? */
	s = bigend - littlelen;
	if (s >= big && bigend[-1] == '\n' && *s == *little
	    /* Automatically of length > 2 */
	    && memEQ((char*)s + 1, (char*)little + 1, littlelen - 2))
	{
	    return (char*)s;		/* how sweet it is */
	}
	if (s[1] == *little
	    && memEQ((char*)s + 2, (char*)little + 1, littlelen - 2))
	{
	    return (char*)s + 1;	/* how sweet it is */
	}
	return NULL;
    }

    if (!valid) {
        /* not compiled; use Perl_ninstr() instead */
	char * const b = ninstr((char*)big,(char*)bigend,
			 (char*)little, (char*)little + littlelen);

        assert(!tail); /* valid => FBM; tail only set on SvVALID SVs */
	return b;
    }

    /* Do actual FBM.  */
    if (littlelen > (STRLEN)(bigend - big))
	return NULL;

    {
	const MAGIC *const mg = mg_find(littlestr, PERL_MAGIC_bm);
	const unsigned char *oldlittle;

	assert(mg);

	--littlelen;			/* Last char found by table lookup */

	s = big + littlelen;
	little += littlelen;		/* last char */
	oldlittle = little;
	if (s < bigend) {
	    const unsigned char * const table = (const unsigned char *) mg->mg_ptr;
            const unsigned char lastc = *little;
	    I32 tmp;

	  top2:
	    if ((tmp = table[*s])) {
                /* *s != lastc; earliest position it could match now is
                 * tmp slots further on */
		if ((s += tmp) >= bigend)
                    goto check_end;
                if (LIKELY(*s != lastc)) {
                    s++;
                    s = (unsigned char *)memchr((void*)s, lastc, bigend - s);
                    if (!s) {
                        s = bigend;
                        goto check_end;
                    }
                    goto top2;
                }
	    }


            /* hand-rolled strncmp(): less expensive than calling the
             * real function (maybe???) */
	    {
		unsigned char * const olds = s;

		tmp = littlelen;

		while (tmp--) {
		    if (*--s == *--little)
			continue;
		    s = olds + 1;	/* here we pay the price for failure */
		    little = oldlittle;
		    if (s < bigend)	/* fake up continue to outer loop */
			goto top2;
		    goto check_end;
		}
		return (char *)s;
	    }
	}
      check_end:
	if ( s == bigend
	     && tail
	     && memEQ((char *)(bigend - littlelen),
		      (char *)(oldlittle - littlelen), littlelen) )
	    return (char*)bigend - littlelen;
	return NULL;
    }
}