K
Kaz Kylheku
In machine language, we can, for instance, disable interrupts, flush an
instruction cache, or save the registers to a stack. To show that everything
that can be done in assembly can be done in C, you have to show how these
things are done. The paper does not show such things.
The paper argues that in the domain of translating calculation formulas,
a compiler can select instructions as well as human programmer. (And that with
some extensions to C, like "char small @0x15;" or "registerx xreg;" we can even
coerce the selection of particular operands to match specific instances of
assembly language.)
This has not been controversial for decades; the paper belongs more in 1966, or
maybe 1976, than in 2006.
Still, even in this restricted domain, there are things compilers will
typically not do. For instance, select some very complex instructions, where it
is difficult to identify the pattern of C code which fits them exactly (but the
assembly language programmer can contrive the surrounding code to exploit the
CISC instruction). Or, custom microcoding: make your own machine language instruction and then use it.
Leveling the field between humans and compilers in this area required the
development of RISC architectures (in which you basically write microcode, so
there are no complex instructions that the programmer could use, and no lower
level microcode kernel to escape into to beat the compiler.)
These days, if you're finding that you can't beat the C compiler by coding in
assembly language, chances are it's in large part because the assembly language
is designed to work well as a target language for C compilers! That has not
historically been the case.
Because of the things that assembly language can do that C really cannot (by
design) assembly language is actually a better tool for bootstrapping a high
quality implementation of some high level languages.
For instance, the best quality Lisp implementations use very little or no C
internally, and, in particular, avoid compiling to C, or using C for run-time
code that is directly called from the language. You don't want the image of a
function, the basic unit of the program, to be controlled by a C compiler
because then you have all these uncertainties such as calling conventions,
register use, etc. that are only specific to a compiler, but specific to how a
given compiler is invoked.