I would like to know if someone is interested to talk about a special class of DSLs named “Architecture-aware languages”.
I try to explain what I’m referring to.
Any programming language assumes an underlying computational model: stack/heap for C, an object model for C++, JVM for JAVA, pure math functions for functional languages (purists will forgive me ).
But there is a “dirty world” (like hard real-time embedded control) where the existence of a formal model is not guaranteed, the underlying model is not enough abstract to assume that everything can be done by reading and writing abstract memory locations. And assembly is not an option because of program complexity and time to market constraints.
Here is a list of interesting topics on the subject. I will be happy to engage discussions about those.
Sometimes you don’t have a stack. Really ? yes… and perhaps you only have a really little stack for storing return addresses but no local variables. This means big issues in registers allocation algorithm. Obviously you are loosing recursion, but in real-time control systems typically it’s not needed.
Looping must be as fast as possible, so compiler has to leverage on specialized instructions, like decrement-and-jump.
Real-time control means that compiler is aware of machine’s clock frequency. Compiler has to guarantee real-time constraints. Complication : clock frequency can vary during program execution for different reasons…
Peripherals are so many, so different, and so directly controlled that they cannot be mapped in memory by generic read/write instructions. Every memory has its own access protocol, and compiler must be aware of that. Again, type system semantics must take care of the following problem, for instance: A := B is not permitted if the architecture doesn’t support direct data movement between peripherals A and B.
Typically the processor has microcode fixed on a ROM, and it has a mechanism for replacing instructions after silicon, to fix bugs. This has a big big big impact on registers allocations strategy to guarantee coherence.
In a multi-processor architecture, a main processor can call procedures on secondary processors.
Compiler must be aware of that, and binary code is mapped properly on different areas of code storage.
Sometimes the relationship between primary and secondary processors is master-slave. Sometimes it’s based on parallel threading. In this case the compiler must be aware that registers can be shared between different machine. Sometimes, you have both mechanisms on the same architecture.
If/else branching must be as fast as possible. Compiler has to rearrange things to guarantee this constraint. Sometimes the compiler has to warn the programmer that the expression being computed, is too slow with respect to real-time constraints.
Compiler must be tailored on a significant number of specialized instructions, i.e. :
check one memory bit and jump accordingly, wait on an hardware event… compiler has also consciousness of interrupt mechanisms.
Finally, the fantastic one: when programmers write micro-code , you don’t have yet the final architecture, so parametric compilation is a big dream… Again, think to the situation where you need to re-use a full software suite on a slightly different architecture, without rewriting the compiler and without the possibility of a virtual machine. Really challenging… Front-end/back-end and an intermediate language is not an option, because you can loose real-time constraints. Interesting can be an intermediate language that mantain real-time info.
Any comment is welcome.