Commit d9a7461297 for perl
commit d9a746129777bed0b96456319a8cc5fe8ca066c4
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date: Sun Oct 11 14:35:17 2026 +0000
regcomp.c: Enable \R (LNBREAK) start class
When `\R` was added in 5.10.0, both a regnode for matching and a start
class for finding candidates were added, but (at least in the first
commit) the start class didn't get wired in for use.
The start class isn't used in blead today, but the code for it remains in
`S_find_byclass` with no nearby comment remarking on why it isn't used.
Since the `LNBREAK` start class seems more performant than the `ANYOF` start
class that is otherwise used, this commit adds a case to
`Perl_re_op_compile` to enable use of the `LNBREAK` start class.
When the start class finds a candidate match quickly, there's no discernible
difference between `LNBREAK` and `ANYOF`. For example:
my $x = "\r\nbob"; for (0 .. 2_000_000) { $x =~ /\R(?:a|b|o){3}/; }
* blead:
```
286.60 msec task-clock # 0.997 CPUs utilized
1,216,583,412 cycles # 4.245 GHz
4,611,480,233 instructions # 3.79 insn per cycle
920,789,702 branches # 3.213 G/sec
87,351 branch-misses # 0.01% of all branches
```
* patched:
```
286.72 msec task-clock # 0.997 CPUs utilized
1,221,483,806 cycles # 4.260 GHz
4,497,331,066 instructions # 3.68 insn per cycle
904,754,197 branches # 3.156 G/sec
82,028 branch-misses # 0.01% of all branches
```
But if much searching has to be done to find the first candidate, `LNBREAK`
is noticeably better. For example:
my $x = ("A"x500_000_000)."\r\nbob"; $x =~ /\R(?:a|b|o){3}/;
* blead:
```
1,542.94 msec task-clock # 0.999 CPUs utilized
7,029,095,549 cycles # 4.556 GHz
34,618,078,066 instructions # 4.92 insn per cycle
6,517,492,546 branches # 4.224 G/sec
1,413,693 branch-misses # 0.02% of all branches
```
* patched:
```
330.02 msec task-clock # 0.998 CPUs utilized
1,466,984,351 cycles # 4.445 GHz
7,115,654,408 instructions # 4.85 insn per cycle
2,016,938,870 branches # 6.112 G/sec
1,326,788 branch-misses # 0.07% of all branches
```
diff --git a/regcomp.c b/regcomp.c
index 6f2455b35d..cecb747844 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2075,6 +2075,8 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
first = REGNODE_AFTER(first);
goto again;
}
+ else if (REGNODE_TYPE(OP(first)) == LNBREAK)
+ RExC_rxi->regstclass = first;
else if (OP(first) == GPOS) {
RExC_rx->intflags |= PREGf_ANCH_GPOS;
first = REGNODE_AFTER_type(first,tregnode_GPOS);
diff --git a/t/re/opt.t b/t/re/opt.t
index 7b63b7c57c..ad7323e3fe 100644
--- a/t/re/opt.t
+++ b/t/re/opt.t
@@ -287,3 +287,8 @@ abc(*ACCEPT)xyz 3 0+abc - -
# Nested branches that should not be flattened
(?:(?:(?:|x)|(?:|y))|(?:(?:|z)|w))q 1 - 0:1+q - empty alternatives; prefix is zero-width, literal floats
+
+# LNBREAK does get its own start class
+\R 1 - - stclass=LNBREAK \R start class
+\Rfoo 4 - 1:2+foo stclass=LNBREAK \R start class with floating substr
+\R+foo 4 - 1+foo skip,stclass=LNBREAK \R+ start class with PLUS and floating substr