Code change:
There are many examples where produces worse code than it should (worse than you'd write by hand, at the very least, and in the case of slices, worse then I think it needs to). You can often work around this by going through a pointer, although this is surprising, and not always an option (for example, it is not an option for users of ). Here's a minimal example extracted from some real code but massaged somewhat: For posterity, the generated code here currently is: (And here is actually better than I was getting in my real code, where it ended up as a branch. That said, this is bad enough to demonstrate the problem). I guess this is because gets passed a which itself may not be aligned to (for example, can't be satisfied). That problem is avoided by going through u8 (as is done with ), since that should always succeed (for non-const which isn't relevant here), and hits the special case to fix ). However, in this case the compiler should know that the pointer is aligned to 4, since it comes from a slice (and the pointer does end up with in the LLVM). I think this means there's no actual reason that must be less efficient than (unless I'm missing something), and the issue is just that our impl doesn't have a fast path for this situation. That said, maybe I'm wrong, and the generated code is bad for some other reason. Either way, it would be very nice for this to do better for the slice use case -- as I mentioned, going through is not viable when is invoked from an API like (I suspect if we can't fix it for , we probably could work around it in more directly, but it would be better to do it in if possible. That said, if I'm wrong about why this is happening, all bets are certainly off). See also , which seems related (and my hunch is that it will be fixed if we fix this issue, at least in this case). CC since . P.S. Sorry that this is a bit of a rambling issue. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Saw, got interested. Some drive-by notes: is exactly the codegen plus an to multiply it by the stride. which is used to gate is necessarily not constant folded. Interestingly, (edit: forgot "removing") the fast path thus seems to and . Everything not derived from successfully constant folds. This , even at -O1, with no changes to . (EDIT: on mobile and can't edit on godbolt, but: the linked code implements incorrectly as where it should be . In this case this does not change the results; the UB results in the optimizer assuming the slice is length zero but this has no impact on the pointer aligning.) I figured this out while trying and failing to add a fast path for . I tried delegating inside which I couldn't get to work, then had the idea to just do it from the outside. Even inside , a is correctly constant folded, so it should be possible to improve perf internally, but I couldn't figure out how to add a correct fast path for that case.
Thanks for the report. I think I have an idea how this can be improved, but I need to think about it a little further to see if it really is correct in all instances and to evaluate if it the tradeoffs in code quality are going to be positive enough to warrant a change I’m thinking of. claim

Related discussion:
text: // ` p' + s'o = 0 mod a' ` // ` o = (a' - (p' mod a')) * (s'^-1 mod a') ` // <del> // The first term is "the relative alignment of `p` to `a`" (divided by the `g`), the second // term is "how does incrementing `p` by `s` bytes change the relative alignment of `p`" (again // divided by `g`). // Division by `g` is necessary to make the inverse well formed if `a` and `s` are not // co-prime. </del> <ins> // The first term is "the relative alignment of `p` to `a`" (divided by the `g`), the // second term is "how does incrementing `p` by `s` bytes change the relative alignment of // `p`" (again divided by `g`). Division by `g` is necessary to make the inverse well // formed if `a` and `s` are not co-prime. </ins> // // Furthermore, the result produced by this solution is not "minimal", so it is necessary <del> // to take the result `o mod lcm(s, a)`. We can replace `lcm(s, a)` with just a `a'`. </del> <ins> // to take the result `o mod lcm(s, a)`. This `lcm(s, a)` is the same as `a'`. </ins> // SAFETY: `gcdpow` has an upper-bound not greater than the number of trailing 0-bits in // `a`.