S_regcppush(pTHX_ const regexp *rex, I32 parenfloor, U32 maxopenparen)
{
    const int retval = PL_savestack_ix;
    const int paren_elems_to_push =
                (maxopenparen - parenfloor) * REGCP_PAREN_ELEMS;
    const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS;
    const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT;
    I32 p;
    GET_RE_DEBUG_FLAGS_DECL;

    PERL_ARGS_ASSERT_REGCPPUSH;

    if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push, %i < 0, maxopenparen: %i parenfloor: %i REGCP_PAREN_ELEMS: %u",
                   (int)paren_elems_to_push, (int)maxopenparen,
                   (int)parenfloor, (unsigned)REGCP_PAREN_ELEMS);

    if ((elems_shifted >> SAVE_TIGHT_SHIFT) != total_elems)
	Perl_croak(aTHX_ "panic: paren_elems_to_push offset %"UVuf
		   " out of range (%lu-%ld)",
		   total_elems,
                   (unsigned long)maxopenparen,
                   (long)parenfloor);

    SSGROW(total_elems + REGCP_FRAME_ELEMS);
    
    DEBUG_BUFFERS_r(
	if ((int)maxopenparen > (int)parenfloor)
	    PerlIO_printf(Perl_debug_log,
		"rex=0x%"UVxf" offs=0x%"UVxf": saving capture indices:\n",
		PTR2UV(rex),
		PTR2UV(rex->offs)
	    );
    );
    for (p = parenfloor+1; p <= (I32)maxopenparen;  p++) {
/* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
	SSPUSHIV(rex->offs[p].end);
	SSPUSHIV(rex->offs[p].start);
	SSPUSHINT(rex->offs[p].start_tmp);
	DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
	    "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"\n",
	    (UV)p,
	    (IV)rex->offs[p].start,
	    (IV)rex->offs[p].start_tmp,
	    (IV)rex->offs[p].end
	));
    }
/* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
    SSPUSHINT(maxopenparen);
    SSPUSHINT(rex->lastparen);
    SSPUSHINT(rex->lastcloseparen);
    SSPUSHUV(SAVEt_REGCONTEXT | elems_shifted); /* Magic cookie. */

    return retval;
}
S_regcppush(pTHX_ const regexp *rex, I32 parenfloor, U32 maxopenparen)
{
    const int retval = PL_savestack_ix;
    const int paren_elems_to_push =
                (maxopenparen - parenfloor) * REGCP_PAREN_ELEMS;
    const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS;
    const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT;
    I32 p;
    GET_RE_DEBUG_FLAGS_DECL;

    PERL_ARGS_ASSERT_REGCPPUSH;

    if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push, %i < 0, maxopenparen: %i parenfloor: %i REGCP_PAREN_ELEMS: %u",
                   (int)paren_elems_to_push, (int)maxopenparen,
                   (int)parenfloor, (unsigned)REGCP_PAREN_ELEMS);

    if ((elems_shifted >> SAVE_TIGHT_SHIFT) != total_elems)
	Perl_croak(aTHX_ "panic: paren_elems_to_push offset %"UVuf
		   " out of range (%lu-%ld)",
		   total_elems,
                   (unsigned long)maxopenparen,
                   (long)parenfloor);

    SSGROW(total_elems + REGCP_FRAME_ELEMS);
    
    DEBUG_BUFFERS_r(
	if ((int)maxopenparen > (int)parenfloor)
	    PerlIO_printf(Perl_debug_log,
		"rex=0x%"UVxf" offs=0x%"UVxf": saving capture indices:\n",
		PTR2UV(rex),
		PTR2UV(rex->offs)
	    );
    );
    for (p = parenfloor+1; p <= (I32)maxopenparen;  p++) {
 
	SSPUSHIV(rex->offs[p].end);
	SSPUSHIV(rex->offs[p].start);
	SSPUSHINT(rex->offs[p].start_tmp);
	DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
	    "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"\n",
	    (UV)p,
	    (IV)rex->offs[p].start,
	    (IV)rex->offs[p].start_tmp,
	    (IV)rex->offs[p].end
	));
    }
 
    SSPUSHINT(maxopenparen);
    SSPUSHINT(rex->lastparen);
    SSPUSHINT(rex->lastcloseparen);
    SSPUSHUV(SAVEt_REGCONTEXT | elems_shifted);  

    return retval;
}