📖C Is Not a Low-level Language

David Chisnall

C is no longer a low-level language

  • C was a low-level language for PDP-11.
  • Modern processors were not just built as fast processors, but as fast emulators of PDP-11. (trying to expose the same abstract machine as a PDP-11). This allowed C programmers to believe that their language is close to the underlying hardware. → Modern processors are fast PDP-11 emulators
  • modern processors inspect adjacent instruction and execute them in parallel if they are independent. This adds a nontrivial amount of complexity (and power consumption), but allows programmers to continue program with sequential logic. GPUs, on the other hand, have no of this logic and require an explicit parallelism.
  • “A modern Intel processor has up to 180 instructions in flight at a time.”
  • Another abstraction of C machine is flat memory. This is no longer true for two decades: processors have multiple levels of caches to hide latency (while preserving the model). → Modern processors are fast PDP-11 emulators
  • Another attribute of low-level languages is that they are fast. i.e., compiler doesn’t have to be too complex or do too much optimization. (This is also no longer true for C.)
  • pointer aliasing is a big part of the reason that C has failed to displace Fortran in high-performance computing.
  • C implies a layout for structures and compiler cannot reorder or change it (e.g., transforming an array of structs into a struct of arrays for better vectorization)
  • Possibly uninitialized values prevent some optimizations → Loop unswitching must pay attention to possibly zero-counted loops (in presence of uninitialized values)
  • the main issue of caches is that they are expected to be both shared and mutable → The main complication for CPU cache is shared and mutable state
    • Sun Labs’ Project Maxwell noted that the first cache line largely corresponds to the first generation that is most likely to be garbage-collected. Thus, it would be beneficial to have a garbage-collector that operates on cache and doesn’t have to write dead objects to main memory.