Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 405
Timesquare Avatar asked Oct 01 '12 14:10

Timesquare


People also ask

Which registers shows the status of the CPU?

The status register is a hardware register that contains information about the state of the processor. Individual bits are implicitly or explicitly read and/or written by the machine code instructions executing on the processor.

How do I access my CPU registers?

CPU registers are accessed by using the names that are predefined in the assembler.

What is the purpose of the condition code register?

We introduce another register, called the Condition Code register. It is used to keep information regarding the results of arithmetic operations, so we can look at them later.

How many bit's are stored in the status register?

The Status Register has 16 bits, with each bit having a flag.


2 Answers

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.

like image 88
Jan Hudec Avatar answered Nov 10 '22 04:11

Jan Hudec


  • 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;
like image 36
Sebastian Mach Avatar answered Nov 10 '22 04:11

Sebastian Mach