Why was no intrinsic access to the CPU's status register in the design of both C and C++?

孤街浪徒 提交于 2019-12-23 09:38:17

问题


In the case of the overflow flag, it would seem that access to this flag would be a great boon to cross-architecture programming. It would provide a safe alternative to relying on undefined behaviour to check for signed integer overflow such as:

if(a < a + 100) //detect overflow

I do understand that there are safe alternatives such as:

if(a > (INT_MAX - 100)) //detected overflow

However, it would seem that access to the status register or the individual flags within it is missing from both the C and C++ languages. Why was this feature not included or what language design decisions were made that prohibited this feature from being included?


回答1:


  • Because C++ is designed as a portable language, i.e. one that compiles on many CPUs (e.g. x86, ARM, LSI-11/2, with devices like Game Boys, Mobile Phones, Freezers, Airplanes, Human Manipulation Chips and Laser Swords).
    • the available flags across CPUs may largely differ
    • even within the same CPU, flags may differ (take x86 scalar vs. vector instructions)
    • some CPUs may not even have the flag you desire at all
  • The question has to be answered: Should the compiler always deliver/enable that flag when it can't determine whether it is used at all?, which does not conform the pay only for what you use unwritten but holy law of both C and C++
  • Because compilers would have to be forbidden to optimize and e.g. reorder code to keep those flags valid

Example for the latter:

int x = 7;
x += z;
int y = 2;
y += z;

The optimizer may transform this to that pseudo assembly code:

alloc_stack_frame 2*sizeof(int)
load_int 7, $0
load_int 2, $1
add z, $0
add z, $1

which in turn would be more similar to

int x = 7;
int y = 2;
x += z;
y += z; 

Now if you query registers inbetween

int x = 7;
x += z;
if (check_overflow($0)) {...}
int y = 2;
y += z;

then after optimizing and dissasembling you might end with this:

int x = 7;
int y = 2;
x += z;
y += z;
if (check_overflow($0)) {...}

which is then incorrect.

More examples could be constructed, like what happens with a constant-folding-compile-time-overflow.


Sidenotes: I remember an old Borland C++ compiler having a small API to read the current CPU registers. However, the argumentation above about optimization still applies.

On another sidenote: To check for overflow:

// desired expression: int z = x + y
would_overflow = x > MAX-y;

more concrete

auto would_overflow = x > std::numeric_limits<int>::max()-y;

or better, less concrete:

auto would_overflow = x > std::numeric_limits<decltype(x+y)>::max()-y;



回答2:


Because C and C++ are designed to be platform independent. Status register is not.

These days, two's complement is universally used to implement signed integer arithmetic, but it was not always the case. One's complement or sign and absolute value used to be quite common. And when C was first designed, such CPUs were still in common use. E.g. COBOL distinguishes negative and positive 0, which existed on those architectures. Obviously overflow behaviour on these architectures is completely different!

By the way, you can't rely on undefined behaviour for detecting overflow, because reasonable compilers upon seeing

if(a < a + 100)

will write a warning and compile

if(true)

... (provided optimizations are turned on and the particular optimization is not turned off).

And note, that you can't rely on the warning. The compiler will only emit the warning when the condition ends up true or false after equivalent transformations, but there are many cases where the condition will be modified in presence of overflow without ending up as plain true/false.




回答3:


I can think of the following reasons.

  1. By allowing access to the register-flags, portability of the language across platforms is severily limited.

  2. The optimizer can change expressions drastically, and render your flags useless.

  3. It would make the language more complex

  4. Most compilers have a big set of intrinsic functions, to do most common operations (e.g. addition with carry) without resorting to flags.

  5. Most expressions can be rewritten in a safe way to avoid overflows.

  6. You can always fall back to inline assembly if you have very specific needs

Access to status registers does not seem needed enough, to go through a standardization-effort.



来源:https://stackoverflow.com/questions/12674969/why-was-no-intrinsic-access-to-the-cpus-status-register-in-the-design-of-both-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!