This [0] post by Stephen Toub goes in GREAT detail on that
[0]: https://devblogs.microsoft.com/dotnet/performance_improvemen...
*I may get vector length wrong, but you get the idea
[0]: https://docs.oracle.com/en/java/javase/19/docs/api/jdk.incub...
If you need the vpshufb behavior of zeroing elements where the index is negative, I think you will need to build something out of multiple operations. The compiler is of course free to match those multiple operations to one target instruction, i.e., recognize that what you are trying to say is really a vpshufb. It can do this in the same way that it can match multiple operations like x + y * 8 + 12 to a single lea instruction.
I am concerned that it takes like 6 instructions (2 to put copies of each lane into all lanes, 2 shuffles, cmpgt, blend) including a load and using an extra register to implement rearrange for use cases that would be fine with vpshufb for 32-byte registers and maybe 14 instructions (4 to put copies of each lane into all lanes, 4 shuffles, 3 compares, 3 blends) with 3 loads and 3 extra registers to implement rearrange for 64-byte registers. Maybe you can do better for the latter case though, I haven't had a thorough try at it.
A common use of vpshufb is to get a mask of character positions from a string matching a small set of characters, which you can do with cmpeq(in_slice, vpshufb(c, in_slice)), where the input substring in_slice is used as the shuffle and c is chosen so that input characters in the set of characters of interest (e.g. {'\n' '\r' '\t' '\"' '\\'}) map to themselves and other characters map to something other than themselves. rearrange doesn't seem to define what happens when indices in the shuffle are negative or too large, so it seems like to use rearrange we need to mask off some bits and do cmpeq(in_slice, rearrange(c, and(d, in_slice))) where the `and` is only there because of the nit about invalid indices and `rearrange` is 1 or 6 or 14 instructions depending on what register width we're working with. That could be unfortunate.
You don't need this stuff for sorting primitives though!
It's a pity because you clearly have a lot of knowledge that you could put to use to provide very helpful feedback to implementors of the Vector API. (I'm doing this for the GraalVM compiler.)
The folks on the JDK side probably didn't even research how to parallelize sort.