Some of the simpler optimizations, sure. But modern backends do many incredibly sophisticated optimizations that are way beyond any kind of simple pattern-matching-and-substitution model.
Even fundamental "optimizations" like register allocation use quite sophisticated algorithms. Optimal register allocation is NP-complete, so compilers use heuristics on top of graph coloring algorithms to do their best.
Most other optimizations rely on type analysis, data flow analysis, liveness analysis, etc.
https://llvm.org/devmtg/2011-11/Olesen_RegisterAllocation.pd...
One of the things that really excites me about Rust is that it's single mutable reference enforcement means you can run run `restrict` 100% of the time if you wanted which is a non-trivial performance boost. I think it's not enabled today but from previous discussions it sounds like that's just a matter of plumbing through the right things to LLVM.
Every time I've seen that rolled out in a C/C++ codebase someone invariably forgets about pointer aliasing and you spend a week tracking down some non-deterministic behavior.
Transmeta's x86 CPU's were even doing translations and optimizations dynamically between x86 and their internal representations.
I think every modern x86 CPU is doing exactly that.
The compiler should offer a macro for that. Then the question is whether to take the specification or the implementation at which point it's an absurd question to begin with. You could compare -O0 binaries, bypassing the optimization question, too.
High/low is not fine grained enough. IIRC, prolog for example would be dubbed a fifth generation language, after assembler, goto hell macro compilers, structured functional programming, and DSLs. Now coq and the like seem to be of yet a higher order (pun intended, sorry).
If you use GCC then __builtin_add_overflow() is what you are looking for:
"The compiler will attempt to use hardware instructions to implement these built-in functions where possible, like conditional jump on overflow after addition, conditional jump on carry etc."
https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins...
IMO C is close to low-level because it's relatively easy to imagine the resulting unoptimized assembly given some piece of code (which is why some people jokes about C being a macro assembly).
Maybe this old debate should get an slight update... and this could be the starting point: Is modern x86 assembly still "low-level"? :)