4 ms·
When deciding on the behavior of some operation that maps to hardware [1], how do you weight the existing hardware behaviors? For example, if all past, current
by BeeOnRope 7y ago
When deciding on the behavior of some operation that maps to hardware [1], how do you weight the existing hardware behaviors?
For example, if all past, current and contemplated hardware behaves in the same way, I assume that the standard will simply enshrine this behavior.
However, what if 99% of hardware behaves one way and 1% another? Do you set the behavior to "undefined" to accommodate the 1%? At what point to you decide that the minority is too small and you'll enshrine the majority behavior even though it disadvantages minority hardware?
---
[1] Famous examples include things like bit shift and integer overflow behavior.
- rseacord 7y agoI would say that the committee does pay attention to hardware variations, even when there are no examples of existing hardware that implement a feature (for example, a trap representation for integers other than _Bool). Some of the thinking is that "if it was ever implemented in hardware, it could be again). I'm not crazy about this thinking, and I largely think that language features for which there are no existing hardware implementations should be eliminated and then brought back if needed. However, the C Committee is much smaller than the C++ committee so there is a labor shortage. More people getting involved would certainly help. We have dropped support for sign and magnitude and one's complement architectures from C2x (a decision Doug Gwyn does not agree with). There was some concern that Unisys may still use a one's complement architecture, but that this may only be in emulation nowadays.
- rseacord 7y agoSome example of hardware variation (since you mentioned shifting and overflow): - signed integer overflow or division by zero occurs, a division instruction traps on x86, while it silently produces an undefined result on PowerPC - left-shifting a 32-bit one by 32 bits yields 0 on ARM and PowerPC, but 1 on x86; - left-shifting a 32-bit one by 64 bits yields 0 on ARM, but 1 on x86 and PowerPC
- BeeOnRope 7y agoOn x86 it's actually mixed: scalar shifts behave as you describe, but vectorised logical shifts flush to zero when the shift amount is greater than the element size! So x86 actually has both behaviors in one box (three behaviors if you could the 32-bit and 64-bit scalar things you mentioned separately). This is an example of where UB for simple operations actually helps even on a single hardware platform: it allows efficient vectorization.
- loeg 7y agoA good example might be 1's complement signed integers. They were dead weight in the standard for a long time.
- BeeOnRope 7y agoYes, but that is a slightly different question: how long you do you keep something in the standard after all the relevant hardware has disappeared, e.g,. is there a framework for periodically re-evaluating decisions in light of the changing hardware landscape. My question was more about when behavior is being defined for the first time, which admittedly doesn't happen that often (but it could apply e.g., when thing fixed-width integer types, uintX_t and friends were introduced).
- DougGwyn 7y agoOriginal standard feature specifications were not meant to obtain a 1-to-1 map from C onto hardware, but we used practical experience to judge what overhead was acceptable for the kinds of processors we had seen or thought were reasonable choices that the architects might make in the not too distant future. If a frequently-executed action had to (for example) check for a special condition every time, the overhead might increase by several percent, depending on the instruction set architecture. So quite often we argued that "if the programmer wants to test for that condition, he can do so, but typically it is a waste of cycles". There are a lot of such trade-offs; maybe we should write a paper or book on this topic.