alpha: Add JIT support - #921
Conversation
|
Is this architecture is still supported by HP? Alpha EV7 is released in 2003. |
It is not supported by HP, no.
Is it causing maintenance issues? I have a passing interest in MIPS and could have a look. Dropping it based on release date doesn't seem like the right metric. |
|
The reasoning is that the jit compiler is normally used in high performance environments. If you have old machines, they are likely not used in production environments. They simply used for "showing that they still works". Supporting them is not worth the maintenance efforts. MIPS is not the first arch which was dropped, sparc and TileGX was also supported at some point of time. Anyway, if somebody is willing to maintaining these architectures, I have no problem supporting these outdated cpus. The problem is that if the maintainer disappears after a few years. I have no resources to maintain them. |
|
Thanks. That makes complete sense to me and I fully agree. I've been working to support old/weird architectures for 15+ years now, so I'm happy to contribute to sljit and pcre2 in that capacity. (Though I cannot promise I won't suddenly be hit by a bus) I'll start by checking on the status of the test suite on mips tomorrow. I found an issue indicating it might be more than a little broken :) |
|
I don't have any particular influence over sljit. I have been struggling with personal to keep up with PCRE2 recently - so anything that keeps maintenance down would be nice. Dead architectures like MIPS or Alpha or Sparc seem totally reasonable to drop. Retrocomputing can focus on keep old software alive on old systems, but doesn't need to bring new software to such systems. Or at least, I don't the time or energy to contribute to that effort personally. I feel like there are several bits of code in PCRE2 (including some z/OS support and VMS) which is clearly broken, and I'm quite confident doesn't compile anymore. It's always painful to "pull the trigger" and delete it. I'm afraid that old sljit architectures would end in the same place: code contributed by one expert, used by one or two users, and then after a couple of years be dead, and with little way for us to know if it still works. |
3175841 to
a360895
Compare
Pulls in the DEC Alpha 64-bit JIT backend (sljit PCRE2Project#364), which the following commits build on, along with the other sljit changes made since the previous update.
a360895 to
3658b9e
Compare
|
The sljit code has landed upstream. Updated this branch to pull that in first. |
|
@zherczeg I can ask Claude and GPT to review this, but otherwise... it's just a total black box to me. I know nothing about Alpha. I presume, since you accepted the PR in sljit, that you're happy to accept the Alpha support in PCRE2? |
|
We need to add the new file to the tarball manifest. I cannot push this change, because maintainer updates to your branch are not turned on, so you'll have to do it yourself. --- a/maint/manifest-tarball
+++ b/maint/manifest-tarball
@@ -57,6 +57,7 @@ drwxr-xr-x tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/allocator_src
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitConfigInternal.h
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitLir.c
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitLir.h
+-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitNativeALPHA_64.c
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitNativeARM_32.c
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitNativeARM_64.c
-rw-r--r-- tarball-dir/pcre2-SNAPSHOT/deps/sljit/sljit_src/sljitNativeARM_T2_32.c |
|
While alpha support is acceptable for sljit, I am not sure about PCRE2. Even with the sljit core code, it should work. I would not go adding a lot of specialized code for PCRE2 though. @NWilson what do you think? |
|
The problem is we have no easy way of reviewing or fixing any issues. I'm really not that excited about adding an architecture that's not been on sale for 20 years. On the hand... I'm not mean, and if a user wants it, I guess I can take it. I have asked GPT to do a very thorough review of all the new Alpha code, and it couldn't find any issues. @mattst88 Is there the possibility of cutting down on the amount of Alpha-specific specialisation so the PCRE2 code that's specific to Alpha is shorter? |
|
We could certainly only land the first two commits and get basic Alpha support. I'll run some benchmarks (or find where I recorded benchmark results while writing this series) and post them. Would it be valuable (in general) to run the PCRE2 tests under QEMU for supported platforms? That's what we do in libunwind and it has helped immensely. I'd be happy to work on that and then we can circle back to this PR once we've built some confidence (in the approach and in me). |
|
We already run our CI tests on a list of processor architectures, and all OSes that we can get our hands on. S/390X, PPC64, ARMv7, AArch64, RiscV64... So we've even got big-endian and 32-bit platforms in there. Unfortunately the GitHub Actions runner we use (run-on-arch-action) doesn't have Alpha. Not surprising really. Honestly - it's over to you to keep it running. If you want to contribute a CI job for that, great. But otherwise, it's just your testing keeping it from bitrot. Personally - I would add the absolute minimum number of lines of code to PCRE2. Why optimise for a platform with so few users? |
|
Okay, I've opened #939 which adds QEMU testing for currently-untested platforms.
Understood. For me, it's a fun challenge. You're certainly under no obligation to indulge me in that. But, I do enjoy contributing upstream, so if you all are willing, I'd prefer the code to be upstream. Happy to contribute to the project outside of that goal as well, of course! |
|
Very well then. I accept it! With your CI additions as well, we'll even be able to actually run the code, which is great. And we're always grateful for contributions. I like your enthusiasm! |
|
This does need a small fix though:
|
|
Okay, here's the story with the follow-on commits. They're pretty important. I made a benchmark that checks a bunch of different cases (which I'll make a PR for, in case it appears to be generally useful).
This is the table of operations in the benchmark: static const struct benchmark benchmarks[] = {
/* Pure fast-forward cost: the first code unit never occurs, so the JIT
* scans the whole buffer and reports NOMATCH without a single false start. */
{ "ff-char-absent", "Q", "single absent char" },
{ "ff-lit-absent", "zqjx", "absent literal, char pair start" },
{ "ff-lit-found", "wombat", "rare literal, present" },
/* Character-range fast-forward. */
{ "ff-range-absent", "[XYZ]", "absent range" },
{ "ff-range-digits", "[0-9]{6}", "sparse digit run" },
{ "ff-class-dense", "[aeiou]qzx", "dense first char, all false starts" },
/* Caseless and pair-based fast-forward. */
{ "ff-caseless-absent", "(?i)zqjx", "caseless absent literal" },
{ "ff-caseless-found", "(?i)Hello", "caseless literal, present" },
{ "ff-pair-common", "th", "very common char pair" },
/* Realistic mixed patterns. */
{ "re-email", "[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}", "email address" },
{ "re-longword", "\\b\\w{12,}\\b", "long word boundary scan" },
{ "re-alt", "(?:wombat|numbat|quokka)", "alternation of literals" },
/* Controls that do not use fast-forward at all; these should be flat across
* every commit in the series and act as a noise floor. */
{ "ctl-anchored", "\\A\\w+", "anchored, no fast-forward" },
{ "ctl-startline", "(?m)^the\\b", "multiline start-of-line" }
};Here are the numbers, per commit. These are throughput in MB/s:
|
List the new sljit Alpha backend sources in EXTRA_DIST and add DEC Alpha 64-bit to the platforms supported by the JIT compiler in the documentation. The corresponding deps/sljit submodule bump is deferred until the backend is merged upstream; validated under qemu-alpha (pcre2_jit_test passes in 8/16/32-bit modes and RunTest passes with and without JIT).
Use the Alpha CMPBGE instruction for 8-byte-at-a-time character scanning in the JIT compiler, similar to how other architectures use SIMD instructions. CMPBGE compares 8 byte pairs and produces an 8-bit mask, which combined with XOR gives us byte-equality matching across a whole quadword at once. Implement fast_forward_char_simd, fast_requested_char_simd, and fast_forward_char_pair_simd. The first-match step uses a base-ISA binary search (NEGQ+AND to isolate the lowest set bit, then three AND+SELECT pairs), identical to glibc's Alpha strchr; no CIX required. For 16/32-bit code units, a post-processing step compacts the per-byte CMPBGE mask into a per-code-unit mask by ANDing adjacent bits. The char-pair function handles Alpha's 8-byte alignment requirement for LDQ by constructing the unaligned second data word from two aligned loads using SRL/SHL/OR.
Emit PREFETCH_L1 (LDL R31) 192 bytes ahead of the current position in all three fast-forward scanning loops: fast_forward_char_simd, fast_requested_char_simd, and fast_forward_char_pair_simd. The 192-byte (3 cache line) prefetch distance matches what glibc's Alpha memchr uses. Without this, the JIT's CMPBGE loop loses to the interpreter's memchr() call on full-scan no-match patterns because memchr has prefetching and software pipelining. The prefetch is guarded by a comparison against STR_END - 192 to avoid reading past the end of the buffer on short haystacks, where unconditional prefetching caused a ~15% regression.
For 8-bit mode with an exact single-character match, call glibc's memchr() instead of the inline CMPBGE scanning loop. glibc's Alpha memchr uses CMPBGE with 3-cache-line-ahead prefetching, cacheline alignment, and software pipelining (overlapping the next load with the current compare to hide L1 latency). The CMPBGE loop is retained for case-insensitive (match1i) and two-character (match2) scanning where memchr does not apply. Both fast_forward_char_simd and fast_requested_char_simd gain the memchr path; fast_forward_char_pair_simd is unchanged since it searches for two characters at different offsets simultaneously.
We have hand-written code for every architecture SLJIT supports, but CI only exercises a few of them. The existing "ptarmigan" job covers s390x, ppc64le, armv7, aarch64 and riscv64, which leaves the 32-bit ARM, PowerPC, MIPS and LoongArch backends untested. The ARM one is easy to miss: Ubuntu's armhf compiler defaults to Thumb-2, so armv7 exercises sljitNativeARM_T2_32.c and never sljitNativeARM_32.c. Add a job which cross-compiles for each of them and runs the test suite under qemu-user. This is a different mechanism to ptarmigan, which boots a container of the target architecture: run-on-arch-action supports only armv6, armv7, aarch64, riscv64, s390x and ppc64le, so none of these targets can be added to it. Cross-compiling is also faster, since only the test programs are emulated rather than the compiler as well. RunTest already accepts a "-sim" prefix for exactly this purpose, so the test scripts need no changes. Shared libraries are disabled so that the test programs are real executables rather than libtool wrapper scripts, which qemu-user cannot run. Both MIPS release 6 and the earlier releases are covered, since SLJIT_MIPS_REV selects different code for each.
Add alpha to the coelacanth matrix, so the new sljitNativeALPHA_64.c backend is exercised by CI like the others. Alpha is not a release architecture, but the cross toolchain and the emulator are both packaged: gcc-14-alpha-linux-gnu and qemu-alpha are available in Ubuntu 26.04, and no extra apt sources are needed. The libc package is named libc6.1-dev-alpha-cross, because Alpha uses libc6.1 rather than libc6, and it provides the libc6-dev-alpha-cross name that the job's "libc" matrix field builds, so the existing install line needs no change. Verified by cross-compiling with gcc 15 and running the full suite under qemu-alpha: RunTest passes with and without JIT, and pcre2_jit_test and pcre2posix_test both pass, in 8-, 16- and 32-bit modes.
3658b9e to
98814f9
Compare
Thank you! I've fixed that and repushed. Note that the PR currently now contains the patch from #939 so that I could add another patch that adds CI support for alpha on top. I expect the other PR to land before this and rebase out of this PR. |
|
Wow. This is the dedication of a true hobbyist (I presume). You don't work with Alpha commercially, do you? Anyway, those performance stats are awesome. We'll take it! |
|
Thank you! Yep, true hobbyist. Just got interested in weird old computers a long time ago and never grew out of it. (I've recently begun restoring the content of the AlphaLinux.org wiki which I originally created in 2008 and was lost when a hard drive failed in ~2011 -- see https://alphalinux.org/wiki/). If this lands, it'll be a news item for the dozens of Alpha users. |

Add JIT compiler support for DEC Alpha (AXP) 64-bit, in four commits:
Base
CMPBGE scanning:
fast_forward_char_simd,fast_requested_char_simd, andfast_forward_char_pair_simdusing the AlphaCMPBGEinstruction for 8-byte-at-a-time character scanning, analogous to the SIMD paths on other architectures. The first-match step uses a base-ISA binary search (NEGQ+AND to isolate the lowest set bit, then three AND+SELECT pairs), identical to glibc's Alpha strchr.memchr:
memchr()instead of the inline CMPBGE loop. glibc's Alpha memchr uses CMPBGE with 3-cache-line prefetching, alignment, and software pipelining that the JIT cannot easily replicate.Prefetching:
PREFETCH_L1(LDL R31) 192 bytes ahead in all three CMPBGE scanning loops. Guarded against short haystacks. Unconditional prefetch caused a ~15% regression on inputs shorter than 192 bytes.Validated on a real HP AlphaServer ES47 (1 GHz EV7):
pcre2_jit_test passesall tests in 8/16/32-bit modes; RunTest passes with and without JIT.The last two commits could be dropped from this PR and considered separately, if desired.
Requires zherczeg/sljit#364