The premise of low-level languages is that the code the processor will execute is very similar to what programmer writes. i.e., you can tell what the processor is gonna do.
This is no longer the case for a couple of reasons:
- C compiler does a ton of optimizations. It can inline functions, reorder instruction, remove data fetches, perform tail calls, etc. The source code might be very different from what is gets executed. And depending on optimizations it can have visibly different results.
- Processors are much more sophisticated nowadays. They can do instruction reordering and speculative code execution. (Modern processors are fast PDP-11 emulators)
C was a low-level language for PDP-11, but that is no longer true for modern processors.
- Modern processors are fast PDP-11 emulators
- Fortran used to be faster than C because of aliasing—aliasing/non-aliasing prevents some optimizations
- Loop unswitching must pay attention to possibly zero-counted loops (in presence of uninitialized values)—allowing uninitialized values prevents some optimizations.