What Is C For?
Since C was originally standardized in 1989, two major versions of the language specification have been released: C89 and C99. With a new version coming out every 10 years, it’s about time for another one.
C has always been a slightly confused language. It was created as a simple language from which it was easy to generate machine code for implementing UNIX in a way that wasn’t tied to a specific architecture. Of course, this is nonsense, because any language as low-level as C makes a lot of assumptions about the underlying architecture. One obvious example in C is that of a flat address space—C has no mechanism for controlling segmentation, because this feature wasn’t available on the machines for which the language was designed.
One of the big changes in the last 10 years is that pretty much every CPU now has some form of vector processor. Unfortunately, it’s impossible to write code in C for that vector processor. Currently, programmers handle the problem in the following ways:
- Use inline assembly.
- Use intrinsic functions (very thin wrappers around CPU instructions).
- Use compiler extensions.
The first two alternatives make the code non-portable across architectures; the last makes it non-portable across compilers.
The way GCC handles the last approach is quite nice. Vector types can be declared with a specified size and then can be used in the same way as scalar quantities. But I’d like to see a vector keyword added to the C standard so this can be done without relying on hacks like GCC’s __attribute__ extension. Vectors should be defined in a way similar to arrays, or via a typedef, so that the following would be valid:
typedef vector int int4;
When you created an int4, you would get a vector of four integers. Any operation performed on it would then be performed on all of the elements. All of the basic operations on scalars, including those defined in math.h, should be extended to work on vector types.
A compiler targeting a chip that doesn’t support the operations would reduce them to sequences of scalar operations, exactly as GCC does now. For chips that have vector units, having the semantics of the operations specified in the code makes generating the correct instructions a lot easier than having to infer them from loops.