Yeah, and the author seems to confuse “works on my machine” with “doesn’t have UB”.
FWIW, I think this is a fine use-case for inline assembly - if you want “what the machine does” semantics as opposed to Rust semantics, that’s how you can get that.
It’s also a use case for compiler builtins that define or change language semantics to whatever it is we need them to be. Rust semantics are only useful if they get the compiler to generate the code we want. If that’s not happening, it’s time to leave them behind.
#[inline(always)]
pub unsafe fn get_partial_unsafe(data: *const State, len: usize) -> State {
let indices =
_mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
// Create a mask by comparing the indices to the length
let mask = _mm_cmpgt_epi8(_mm_set1_epi8(len as i8), indices);
// Mask the bytes that don't belong to our stream
return _mm_and_si128(_mm_loadu_si128(data), mask);
}
You can generate the mask by reading from a buffer at an offset. It will save you a couple of instructions:
e: of course this comes from somewhere - found this dumb proof of concept / piece of crap i made forever ago https://files.catbox.moe/pfs2qu.txt (point to avoid page faults; no other ‘bounds’ here..)
The very first comment in the article condemns these impressive results due to undefined behavior and goes on to suggest that compilers are “allowed” to generate broken code. Looks like Rust is following C’s footsteps…
If the language’s semantics are insufficient, they should give us a rich set of built in features that tweak the compiler’s expectations. Instead of “optimizing” in an adversarial, borderline malicious way, the compiler should require the programmer to define the undefined behavior. After the code is compiled, the compiler’s expectations are irrelevant, only the system’s expectations matter. Those are the ones we care about.
The Linux kernel is compiled with behavior defining flags such as:
The last item is especially noteworthy. Compilers “optimizing” by deleting null pointer checks because they “know” it can’t be null because some standard said so has turned bugs into exploitable vulnerabilities. Stuff like this shouldn’t be normalized.
Note that this is using undefined behavior, so it’s unsound and could break at any time.
https://github.com/ogxd/gxhash/issues/82 (there’s a concurring comment from Ralf Jung, who would know what he’s talking about.)
Yeah, and the author seems to confuse “works on my machine” with “doesn’t have UB”.
FWIW, I think this is a fine use-case for inline assembly - if you want “what the machine does” semantics as opposed to Rust semantics, that’s how you can get that.
It’s also a use case for compiler builtins that define or change language semantics to whatever it is we need them to be. Rust semantics are only useful if they get the compiler to generate the code we want. If that’s not happening, it’s time to leave them behind.
In this:
You can generate the mask by reading from a buffer at an offset. It will save you a couple of instructions:
I feel like this line is missing an addition of 16? And also probably a cast or two so that the pointer arithmetic works out correctly?
why trying to do this crap in c is always a mistake
e: ‘better’ (no overread):
of course overread is actually fine…
e: of course this comes from somewhere - found this dumb proof of concept / piece of crap i made forever ago https://files.catbox.moe/pfs2qu.txt (point to avoid page faults; no other ‘bounds’ here..)
Correct. I shouldn’t write comments late in the evening…
The very first comment in the article condemns these impressive results due to undefined behavior and goes on to suggest that compilers are “allowed” to generate broken code. Looks like Rust is following C’s footsteps…
If the language’s semantics are insufficient, they should give us a rich set of built in features that tweak the compiler’s expectations. Instead of “optimizing” in an adversarial, borderline malicious way, the compiler should require the programmer to define the undefined behavior. After the code is compiled, the compiler’s expectations are irrelevant, only the system’s expectations matter. Those are the ones we care about.
The Linux kernel is compiled with behavior defining flags such as:
The last item is especially noteworthy. Compilers “optimizing” by deleting null pointer checks because they “know” it can’t be null because some standard said so has turned bugs into exploitable vulnerabilities. Stuff like this shouldn’t be normalized.