6 ms·
But as you know, CPU ISAs are designed for C programs and compilers are optimized for C programs. So everything, even new languages like Rust, have to buy into
by ChrisSD 8y ago
But as you know, CPU ISAs are designed for C programs and compilers are optimized for C programs. So everything, even new languages like Rust, have to buy into C's model to some extent.
Truly getting out from under C's shadow is going to be very difficult. Maybe better languages are a first step on that path but they are only a small step.
- pjmlp 8y agoModern CPUs, but it used to be that they were designed for any high level language before C took over the show.
- jstimpfle 8y agoThat is said a lot, but what are actual desicions that are made to conform to the C model? What would be good ideas in CPU design that aren't made since they are not compatible with C? (I get it that CPUs have to support some common paradigms and use cases. For example, virtual memory / process isolation, maybe branch prediction things, or support for calling conventions. However, I don't think that is specific to C).
- brandmeyer 8y agoSupport for unaligned memory accesses in hardware is one. The exceeding majority of variable accesses are through pointers of the correct type, and are therefore to variables that are at least naturally aligned. But a very small handful of systems/procedures make unaligned accesses through type-punned pointers. Rather than just crash on these programs, processors will perform multiple memory accesses and stitch the results back together in hardware (worst case behavior: accesses that cross page boundaries). So there's extra hardware to perform this extra state tracking and detect the unaligned accesses in the first place. Hardware doesn't just get turned off for conforming programs. Its there consuming energy and giving off heat on all of them. Edit/addendum Here's another example: What should hardware do on integer overflow? There are several options, including signed-saturation, unsigned saturation, unsigned wraparound, and trap. The semantics of C are such that most hardware just picks 'unsigned wraparound' and makes programs eat the consequences. If you're very lucky then you also get 'an overflow bit, that gets clobbered on the next instruction'. One way to think about this problem might be to ask the question, "What hardware features would reduce the runtime cost of instrumenting programs with the various sanitizers that are becoming available?"
- j16sdiz 8y agoAfaik, sparcs and many other traditional unix-running cpus does not support unaligned memory access
- jschwartzi 8y agoTechnically, neither does ARM. Although you can enable emulation for unaligned accesses. One of the first things I did when setting up QNX was enabling emulation for unaligned accesses to eliminate a SIGBUS termination on some of our applications.
- monocasa 8y agoARM supports it now, and with next to no perf cost.
- jstimpfle 8y agoRegarding alignment, I think it's not C that caused aligned reads to be the standard, but rather hardware itself. There isn't anything in C that prevents unaligned reads, is there? Aligned reads are just a consequence of storing data as vectors of a type, which is a very natural and efficient approach. Unless that's somehow a bad idea or prevents other good ideas, the point is moot. Also caching and page boundaries have nothing to do with C. They are hardware issues (that good C programmers have to deal with, but anyway). Contemporary Intel x86 haven't had significant problems with unaligned reads for a long time; do a web search for Lemire's post. (I guess there are still restrictions for atomic reads/writes). I've long wanted to have access to overflow bits or traps on overflow. C certainly isn't in the way of adding them to CPUs, and signed overflow is even undefined in C, which is an opportunity to make them emit a signal or other exeptions. But I agree, C culture did not require hardware vendors to add overflow bits or traps, so maybe that is C's fault.
- slededit 8y ago> Hardware doesn't just get turned off for conforming programs. Its there consuming energy and giving off heat on all of them. Idle CMOS transistors don't have very much leakage current. They do consume some power but not much. Intel has gotten a lot better about clock gating ensuring more of the chip is truly idle.
- lmm 8y agoVery speculative, don't take any of this as gospel: The very concept of "the stack" implies a C-style evaluation model. Having a single address space for both code and data mainly just gives an opportunity for optimisation to fail. Everything-is-mutable gives a lot of opportunity for optimisation to fail. The compiler wants the program in SSA form, it register-allocates to a bunch of reused names, only for the CPU microcode to figure out which uses of those names can actually be used to mean separate physical registers. Arguably the failure of VLIW (in particular Itanium) was because of C: those processors could (maybe) have run more constrained languages very fast, but it was difficult to compile C to run fast on them.
- jstimpfle 8y agoThe stack is one of those things that would fall under "support for common paradigms". I checked that PDP-11 (the machine on which C was created) already had a hardware stack - and probably even older machines. There are many other programming languages that have the concept of a call stack. Hardware stacks are just an optimization to support this paradigm, and you are not required to use it. Conversely, C does not require any hardware support for implementation of the call stack. The main problem with hardware call stacks is that they can't be relocated if you need predictable performance and/or have pointers instead of offsets into the stack. That means they are bounded size. With 64-bit addresses that may be less of a problem, but still. Functional language do not need to use the hardware stack, so that shouldn't be an issue. > Having a single address space for both code and data mainly just gives an opportunity for optimisation to fail. I don't think C requires that in any way, but since void pointers are allowed to point to either code or data, representation of void pointers must be somewhat "compatible" with both address spaces. > Everything-is-mutable gives a lot of opportunity for optimisation to fail. Not a hardware issue. Also not everything is mutable, not even in C. But you need some mutability for performance even at more abstract levels.
- betterunix2 8y ago"The stack is one of those things that would fall under "support for common paradigms"." Maybe for imperative languages where there is no support for lambda expressions (like C), but in Lisp or in functional languages call stacks are not part of the basic semantics. To put this in C terms, compilers for those languages will rewrite functions to take an extra argument called the "continuation", which is itself a pointer to a function, that is called when a function "returns." The result is that all function calls are tail calls, and by heap-allocating arguments and local variables (which is also necessary because it is possible to create and return a lexical closure), no call stack is needed (but you do wind up relying on a garbage collector). Other continuations are also used e.g. to support exceptions in Common Lisp.
- betterunix2 8y ago"That is said a lot, but what are actual desicions that are made to conform to the C model?" Among other things, special instructions to support a function call stack, which is very much specific to the C model. In Lisp the call stack is unnecessary because of the use of continuation passing style, which implies that all function calls are tail calls and mostly requires that everything be heap-allocated (many compilers will use a call stack as an optimization to avoid excessive garbage collections; unlike C, it is not a fundamental part of the lower level semantics). If you wanted to design a CPU for Lisp or functional languages, you would probably choose to provide special instructions to support continuation passing style or normal order evaluation. You could also imagine a CPU that does not support general pointer arithmetic or which has some form of built-in array bounds checks, which would all be fine if supporting C were not a requirement.
- slededit 8y agoX86 does have array bounds checking now with MPX. Further everything you've mentioned is useful to all languages including the stack. Can you give an example of a negative trade off made for C?
- jstimpfle 8y agoRight. That's what I actually wanted to ask with my first question (but didn't).
- betterunix2 8y agoIn some languages a call stack is only useful as an optimization and some other form of control flow must be emitted for certain constructs that violate the stack paradigm (e.g. call/cc in Scheme, conditions/restarts in Common Lisp). C is also one of the only languages where general pointer arithmetic is necessary; in most languages used today more restricted forms of pointer arithmetic would be more than adequate. I am not saying these are negative tradeoffs as far as the ISA goes, but it is absolutely the case that modern CPUs are designed with C (or some similar language) in mind.
- 8y ago
- fpoling 8y agoTo get the max performance on modern CPU the code has to be cache-aware. It is painful to program for that in C. One often ends up with very complex macros or writing code generators that writes CPU-specific C code. So modern ISA are not designed for C. By such arguments one can claim that CPU are designed for Fortran as it's compilers allows to write fast code with less efforts than in C/C++.
- pjmlp 8y agoActually NVidia's Volta was designed specifically for running C++ code. http://cppcast.com/2017/09/olivier-giroux/ http://cppcast.com/2017/09/olivier-giroux/ https://www.youtube.com/watch?v=Ud1savVLALA https://www.youtube.com/watch?v=Ud1savVLALA
- mhh__ 8y agoI think it is fair to say that modern ISA are built around a C-speaking world if that's more reasonable. This may also be especially true - on a technicality: Does the ISA actually specify the exact cache structure of a CPU? If not, then it is definitely reasonable to say that the ISA (if not the whole microarchitecture?) then is designed with C in mind.
- fpoling 8y agoSurely nobody designs ISA that performs badly for C programs. But it does not mean that it was designed to run average C programs optimally. If one searches for "data oriented programming", then a typical link is about game programming and how using struct of arrays instead of array of structs improves performance due to better cache locality. But such struct of arrays are hard to use and maintain in a general purpose code. It works ok only in game engines or in numerical code when one have a lot of things with the same attribute and the total number of different attributes is low. So if anything, ISA is tailored to allow max performance when coding games or numerical recepeices in particular style. That style is not feasible to apply, for example, in kernel as C has very poor support for it and one gets too many different attributes to get real benefits from following such style.