re_intuit_start(): add some more code comments
re_intuit_start(): bias last* vars; revive reghop4

In the "just matched float substr, now match fixed substr" branch,
initially add an extra prog->anchored_offset to the last and last2 vars;
since a lot of the later calculations involve adding anchored_offset,
doing this early to the last* vars means less work in some cases. In
particular, last is calculated from s by a single

    HOP4(s, prog->anchored_offset-start_shift,...)

rather than two separate

    HOP3(s,   -start_shift,...);
    HOP3(..., prog->anchored_offset,...);

which may mostly cancel each other out.

Similarly with last2. Later, we can skip adding prog->anchored_offset to
last1, since its antecedents already have the bias added.

In the case of failure, calculating a new start position involves an extra
HOP to s, but removes a HOP from other_last, so the two cancel out.

To make this work, I revived the reghop4() function which had been
commented out, and added a HOP4c() wrapper macro. This is like HOP3c(),
but allows you to specify both lower and upper limits. Useful when you
don't know the sign of the offset in advance.

(Yves had earlier added this function, but had commented it out until such
time as it was actually used.)

I also added some extra comments to this block and removed the comment
about it being maybe broken under utf8, since I'm auditing the code for
utf8-safeness.
Perl_regexec_flags(): use HOP4c in another place

Now that we have this macro, use it.
re_intuit_start(): thinko from a few commits ago

I bit of code I modified a few commits ago was supposed to be
subtracting the offset 'start_shift' if it was positive, but the
test condition I coded was 'end_shift > 0' by mistake.

It turns out this is harmless, since start_shift is always positive
anyway, and if the shift wasn't subtracted, it just made the code slightly
less efficient. (So it worked either way).

Fix it any way.
re_intuit_start(): simplify fixed offset_max code

Since we now assert that all offsets are non-negative, this code can
be simplified a bit. Also, by using HOP3lim() rather than HOP3(), we can
remove a trailing conditional.
re_intuit_start(): substr SV cannot be undef

Commit 7e0d5ad7c removed the code that sometimes set the substr
to &PL_sv_undef, so there's no need to test for that value any more.
re_intuit_start(): use different var for tmp value

Make the anchored branch more similar to the floating branch by using s to
hold the start position for fbm rather than t.  Should be functionally
equivalent.

Note that on failure in the anchored branch, we leave with t holding a
different value than before, but it shouldn't matter, since the value of t
is only used in the success case.
re_intuit_start(): introduce rx_origin var

re_intuit_start() is a bit of mess. It uses two general function-scope
vars, s and t, to point at string offsets while processing. These vars
mean different things at different times. Introduce a new var, rx_origin,
which indicates the current minimum position that the regex could begin
matching at. It starts off at strpos, and gradually moves up as various
constraints are rejected. It will be the value eventually returned.

For the moment, s and/or t will continue serving that function at various
points in the code; this commit just makes rx_origin valid at the entry to
the 'restart:' block.
re_intuit_start(): use the rx_origin var more

Make the rx_origin variable (introduced in the previous commit, and which
specifies the current minimum legal place the regex could match at) to
also be used at the start and end of the "other" substr match: the origin
is now passed in this var to the other parts of the code that use it,
rather than in the anonymous "t" variable, which is slowly being reduced
in function to a temporary generic char pointer.
regex substrs: record index of check substr

Currently prog->substrs->data[] is a 3 element array of structures.
Elements 0 and 1 record the longest anchored and floating substrings,
while element 2 ('check'), is a copy of the longest of 0 and 1.

Record in a new field, prog->substrs->check_ix, the index of which element
was copied. (Eventually I intend to remove the copy altogether.)

Also for the anchored substr, set max_offset equal to min offset.
Previously it was left as zero and ignored, although if copied to check,
the check copy of max *was* set equal to min. Having this always set will
allow us to make the code simpler.
re_intuit_start(): update rx_origin after check

Previously the code for updating rx_origin after a 'check' match or an
'other' match looked a bit like this:

    s = fbm_instr(check);

    if (other exists) {
        if (other is anchored) {
            rx_origin = HOP3c(s, -prog->check_offset_max);
            ....
        }
        else {
            rx_origin = HOP3c(s, -prog->check_offset_min);
            ....
        }
    }
    else
        rx_origin = HOP3c(s, -prog->check_offset_max);

This commit changes it to

    s = fbm_instr(check);
    rx_origin = HOP3c(s, -prog->check_offset_max);

    if (other exists) {
        if (other is anchored) {
            ....
        }
        else {
            ....
        }
    }

Of course in each case the 'HOP3' code was slightly different, but they
all happened to be equivalent, especially as for an anchored string,
check_offset_min == check_offset_max.

The only complication was a goto do_other_anchored, but it turns
out that setting rx_origin in that case was easy.
re_intuit_start(): fixup some code comments

Based on some feedback from Hugo, this makes some of the comments I've
added recently less confusing (hopefully).

In particular, it standardises on one set of terminology for string
positions: earliest/first to latest/last, avoiding others like
smallest/least/minimum to greatest/most/maximum, and
bottom/lowest to top/highest.
re_intuit_start(): add tmp assertion

This assertion confirms it is safe to strip out some redundant code that
will be removed (and explained) in the next commit
re_intuit_start(): simplify other=anchored block

This block of code calculates 2 limits: last, last2; plus a third,
last1 = min(last, last2)

It turns out that (as explained below), last is always <= last2, which
allows us to simplify the code. In particular, this means that last always
equals last1, so eliminate last1 and always use last instead.
At the same time, rename last2 to last1, so the vars have the same names /
meanings as in the other=float branch.

Here's the math (ignoring char/byte differences for simplicity's sake):

    last  = s (== start of just matched float substr)
                    - float_min_offset
                    +  anchored_offset
    last2 = strend - minlen + anchored_offset

Let

    delta = last2 - last

          =   (strend - minlen + anchored_offset)
            - (s - float_min_offset + anchored_offset)

          =  (strend  - s) - (minlen - float_min_offset) [1]

Now, we've just matched a floating substring at s. But this previous
match was constrained to *end* no later than end_shift chars before
strend,  so it was constrained to *start* no later than
end_shift + length(float) chars before strend; i.e.

    strend - s >= end_shift + length(float) [2].

Also, more or less by definition,

    minlen = float_min_offset + length(float) + end_shift
or
    end_shift = minlen - float_min_offset - length(float) [2]

So, combining [2] and [3] gives

    strend - s >= (minlen - float_min_offset - length(float)) + length(float)
    strend - s >= minlen - float_min_offset

Therefore, from [1],

    delta >= 0
re_intuit_start(): harmonise other_last++

In the other=anchored branch, at the end on failure or success, we
set other_last to HOP3(last, 1) or HOP3(s, 1) respectively,
indicating the minimum point we should start matching if we ever
have to try again. Clearly for failure, we know the substring can't be
found at any position up to, or including last, so next time we should try
at last+1. For success, if we return later it means that some other
constraint failed, and we already know that the substr wasn't found at
positions up to s-1, and that if we tried position s again we'd just
repeat the previous failure. So in both cases set to N+1.

In the other=float branch however, other_last is set to last or s on
failure or success, with a big "XXX is this right?" against the
"other_last = s" code. It turns out that "other_last = s" *is* right, for
the special reasons explained in the code comments added by this commit;
while "other_last = last" is changed to be "other_last = HOP3(last,1)".
re_intuit_start(): reduce use of *_offset macros

There are a number of macros with definitions like

    #define anchored_offset substrs->data[0].min_offset
    #define float_min_offset substrs->data[1].min_offset

In the two "other substr" branches, replace uses of these macros, e.g.

    {
        ...
        foo = prog->float_min_offset;
        ...
    }

with

    {
        struct reg_substr_datum *other = &prog->substrs->data[other_ix];
        ...
        foo = other->min_offset;
        ...
    }

As well as making debugging easier (a debugger might display real fields
but not macros), and potentially making the binary more compact and faster
(unless the compiler is clever enough to optimise away every use of the
'prog->substrs->data[0]' dereference), it also helps make the two "other
substr" branches more similar, bringing us closer to eventually merging
them.
re_intuit_start(): move do_other_anchored label up

The "other substr" code currently looks like

    if (anchored) {
      do_other_anchored:
        {
            ...
        }
    }
    else {
        ....
    }

Replace it with

  do_other_substr:
    if (anchored) {
            ...
    }
    else {
        ....
    }

and make the two places that currently do 'goto do_other_anchored'
do 'goto do_other_substr' instead, after first asserting that the "other
substr" is indeed always anchored.

This would appear to be infinitesimally less efficient, but is is part
of plan to make the two branches of the "other substr" code more similar,
allowing eventually merging.
re_intuit_start(): re-indent after brace removal

The previous commit removed one level of {} from a block of code;
re-indent to match.

Whitespace-only change
re_intuit_start(): move a line of code earlier

This makes no functional difference, but makes the two branches
of "other substr" calculate the three values last1, last, s in the same
order.
re_intuit_start(): calc fbm_instr() end in bytes

When calculating the end limit of the string to pass to fbm_instr(),
we usually have a pointer to the latest point where the substr could
start, whereas fbm_instr() expects a pointer to the latest point where
the substr could end.

Since fmb_intr() purely matches bytes (it cares not whether those bytes
are part of a utf8 stream of not), the value of the latest end point will
always be:

    (latest start point) + SvCUR(sv) - !!SvTAIL(sv)

i.e. work in bytes, even if we have utf8 values.

In some of the places where fbm_instr() is used, the calculation is being
done partially or fully in chars rather than bytes. This is not incorrect,
and indeed may in theory calculate a slightly lower end limit sometimes
and thus stop the fbm earlier. But this comes at the cost having to do
utf8 length calculations and HOPs back from the end of the string.

So we're trading off not having to do utf8 skips on the last few chars
against the fbm not uselessly searching the last few chars. These roughly
cancel each other out. But since we no longer do HOPs before starting the
fbm, we win every time the fbm doesn't get near the end of the string.

So in conclusion, simpler code and better than or equal performance.