Now, in the case of programming languages, it is quite understandable, because the target machines (be it called "native" or "virtual"), and intermediate representations are target machines, may lack features and thus render expressing the code of the source language more difficult than it should be.
If we take only one example, examine the fundamental difference between two languages like C and Lisp, where it is assumed that the bit patterns in memory representing values are "untyped" in the case of C, but "typed" in the case of lisp. That is, a given bit pattern can be interpreted in C depending on WHERE it is found: if found in a variable of type int, it will be interpreted as an integer modulo 2^32; if found in a variable of type double* it will be interpreted as a pointer to a double floating point number. On the other hand, in lisp, the bit pattern is "typed", and it will be interpreted the same, wherever it is copied to. Unfortunately, unless you have the chance of running a Lisp Machine, you will run your lisp programs on hardware that is designed and optimized for programs written in C, where bit patterns in memory are untyped, and therefore the lisp compilers will have to implement this abstraction adding a layer of interpretation. Specifically, usually a few bits in each word are reserved to store a type tag, so that one may distinguish words containing pointers from words containing pointers of a certain type, or pointers of another.
Now consider LLVM, and consider implementing a language which requires typed data like lisp, and you'll realize that LLVM matches the C kind of machines with "untyped" bit patterns more than the lisp kind, and that therefore it won't make a good IR for lisp-like languages (python, ruby, javascript, etc).
This is not to say that it's impossible to target LLVM when writing those language, on the contrary. But it would be considered as a target language, and evaluated as such, and not as an intermediate representation on which significant and meaningful (for the lisp programs) optimizations can be performed.
1 comment
[ 3.3 ms ] story [ 10.5 ms ] threadIf we take only one example, examine the fundamental difference between two languages like C and Lisp, where it is assumed that the bit patterns in memory representing values are "untyped" in the case of C, but "typed" in the case of lisp. That is, a given bit pattern can be interpreted in C depending on WHERE it is found: if found in a variable of type int, it will be interpreted as an integer modulo 2^32; if found in a variable of type double* it will be interpreted as a pointer to a double floating point number. On the other hand, in lisp, the bit pattern is "typed", and it will be interpreted the same, wherever it is copied to. Unfortunately, unless you have the chance of running a Lisp Machine, you will run your lisp programs on hardware that is designed and optimized for programs written in C, where bit patterns in memory are untyped, and therefore the lisp compilers will have to implement this abstraction adding a layer of interpretation. Specifically, usually a few bits in each word are reserved to store a type tag, so that one may distinguish words containing pointers from words containing pointers of a certain type, or pointers of another.
Now consider LLVM, and consider implementing a language which requires typed data like lisp, and you'll realize that LLVM matches the C kind of machines with "untyped" bit patterns more than the lisp kind, and that therefore it won't make a good IR for lisp-like languages (python, ruby, javascript, etc).
This is not to say that it's impossible to target LLVM when writing those language, on the contrary. But it would be considered as a target language, and evaluated as such, and not as an intermediate representation on which significant and meaningful (for the lisp programs) optimizations can be performed.