saturating_add has to account for negative overflow too, i.e. i32::MIN.saturating_add(-1) should be i32::MIN, while your implementation would return i32::MAX. Though this could be optimized when some operand is constant.
I suppose it is impossible with llvm, because of rustc generates @llvm.sadd.sat.i32 arg, 1 for a.saturating_add, so llvm can not execute any optimisations passes, except target backend,
but it is too late for constant folding and expressions elimination and so on things, that happens before target backend.
So may be usage of instrict for a.saturating_add is not so good idea?
While it is "more difficult" of an optimization (due to being target specific), LLVM is absolutely capable of lowering sadd.sat.i32(arg0, const 1) differently than sadd.sat.i32(arg0, arg1). So it is "just" a missed optimization on their part that could be added.
Also worth noting that if vectorization kicks in, LLVM knows to turn saturating_add directly into a saturating addition. See Compiler Explorer for an example, where LLVM uses PADDUSW to handle the addition, which is a packed saturating add.