Change:
} } <ins> let addr = p.addr(); </ins> let stride = mem::size_of::<T>(); // SAFETY: `a` is a power-of-two, therefore non-zero. let a_minus_one = unsafe { unchecked_sub(a, 1) }; <del> if stride == 1 { // `stride == 1` case can be computed more simply through `-p (mod a)`, but doing so // inhibits LLVM's ability to select instructions like `lea`. Instead we compute </del> <ins> if stride == 0 { // SPECIAL_CASE: handle 0-sized types. No matter how many times we step, the address will // stay the same, so no offset will be able to align the pointer unless it is already // aligned. This branch _will_ be optimized out as `stride` is known at compile-time. let p_mod_a = addr & a_minus_one; return if p_mod_a == 0 { 0 } else { usize::MAX }; } // SAFETY: `stride == 0` case has been handled by the special case above. let a_mod_stride = unsafe { unchecked_rem(a, stride) }; if a_mod_stride == 0 { // SPECIAL_CASE: In cases where the `a` is divisible by `stride`, byte offset to align a // pointer can be computed more simply through `-p (mod a)`. In the off-chance the byte // offset is not a multiple of `stride`, the input pointer was misaligned and no pointer // offset will be able to produce a `p` aligned to the specified `a`. </ins> // <del> //    round_up_to_next_alignment(p, a) - p </del> <ins> // The naive `-p (mod a)` equation  inhibits LLVM's ability to select instructions // like `lea`. We compute `(round_up_to_next_alignment(p, a) - p)` instead. This // redistributes operations around the load-bearing, but pessimizing `and` instruction // sufficiently for LLVM to be able to utilize the various optimizations it knows about. </ins> // <del> // which distributes operations around the load-bearing, but pessimizing `and` sufficiently // for LLVM to be able to utilize the various optimizations it knows about. return wrapping_sub(wrapping_add(addr, a_minus_one) & wrapping_sub(0, a), addr); } </del> <ins> // LLVM handles the branch here particularly nicely. If this branch needs to be evaluated // at runtime, it will produce a mask `if addr_mod_stride == 0 { 0 } else { usize::MAX }` // in a branch-free way and then bitwise-OR it with whatever result the `-p mod a` // computation produces. // SAFETY: `stride == 0` case has been handled by the special case above. let addr_mod_stride = unsafe { unchecked_rem(addr, stride) }; </ins> <del> let pmoda = addr & a_minus_one; if pmoda == 0 { // Already aligned. Yay! return 0; } else if stride == 0 { // If the pointer is not aligned, and the element is zero-sized, then no amount of // elements will ever align the pointer. return usize::MAX; </del> <ins> return if addr_mod_stride == 0 { let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a); let byte_offset = wrapping_sub(aligned_address, addr); // SAFETY: `stride` is non-zero. This is guaranteed to divide exactly as well, because // addr has been verified to be aligned to the original type’s alignment requirements. unsafe { exact_div(byte_offset, stride) } } else { usize::MAX }; </ins> } <del> let smoda = stride & a_minus_one; </del> <ins> // GENERAL_CASE: From here on we’re handling the very general case where `addr` may be // misaligned, there isn’t an obvious relationship between `stride` and `a` that we can take an // advantage of, etc. This case produces machine code that isn’t particularly high quality, // compared to the special cases above. The code produced here is still within the realm of // miracles, given the situations this case has to deal with. </ins> // SAFETY: a is power-of-two hence non-zero. stride == 0 case is handled above. <del> let gcdpow = unsafe { intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)) }; </del> <ins> let gcdpow = unsafe { cttz_nonzero(stride).min(cttz_nonzero(a)) }; </ins> // SAFETY: gcdpow has an upper-bound that’s at most the number of bits in a usize. let gcd = unsafe { unchecked_shl(1usize, gcdpow) }; // SAFETY: gcd is always greater or equal to 1. if addr & unsafe { unchecked_sub(gcd, 1) } == 0 { // This branch solves for the following linear congruence equation:

Discussion:
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