Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is it known that variables are in registers, or on stack?

I am reading this question about inline on isocpp FAQ, the code is given as

void f() {   int x = /*...*/;   int y = /*...*/;   int z = /*...*/;   // ...code that uses x, y and z...   g(x, y, z);   // ...more code that uses x, y and z...  } 

then it says that

Assuming a typical C++ implementation that has registers and a stack, the registers and parameters get written to the stack just before the call to g(), then the parameters get read from the stack inside g() and read again to restore the registers while g() returns to f(). But that’s a lot of unnecessary reading and writing, especially in cases when the compiler is able to use registers for variables x, y and z: each variable could get written twice (as a register and also as a parameter) and read twice (when used within g() and to restore the registers during the return to f()).

I have a big difficulty understanding the paragraph above. I try to list my questions as below:

  1. For a computer to do some operations on some data which are residing in the main memory, is it true that the data must be loaded to some registers first then the CPU can operate on the data? (I know this question is not particularly related to C++, but understanding this will be helpful to understand how C++ works.)
  2. I think f() is a function in a way the same as g(x, y, z) is a function. How come x, y, z before calling g() are in the registers, and the parameters passed in g() are on the stack?
  3. How is it known that the declarations for x, y, z make them stored in the registers? Where the data inside g() is stored, register or stack?

PS

It's very hard to choose an acceptable answer when the answers are all very good(E.g., the ones provided by @MatsPeterson, @TheodorosChatzigiannakis, and @superultranova) I think. I personally like the one by @Potatoswatter a little bit more since the answer offers some guidelines.

like image 677
Allanqunzi Avatar asked Aug 30 '15 16:08

Allanqunzi


People also ask

Are registers stored on the stack?

At the beginning of a function, the current contents of the registers used by the calling program are stored onto the stack memory using PUSH operations, and at the end of the function, the data on the stack memory is restored to the registers using POP operations.

How are local variables stored on the stack?

The stack is used for dynamic memory allocation, and local variables are stored at the top of the stack in a stack frame. A frame pointer is used to refer to local variables in the stack frame.

Where is register variable stored?

Register variables are stored in registers. Static variable is stored in the memory of the data segment. In register variables, CPU itself stores the data and access quickly.

What is used of variable registers?

Register variables tell the compiler to store the variable in CPU register instead of memory. Frequently used variables are kept in registers and they have faster accessibility. We can never get the addresses of these variables. “register” keyword is used to declare the register variables.


1 Answers

Don't take that paragraph too seriously. It seems to be making excessive assumptions and then going into excessive detail, which can't really be generalized.

But, your questions are very good.

  1. For a computer to do some operations on some data which are residing in the main memory, is it true that the data must be loaded to some registers first then the CPU can operate on the data? (I know this question is not particularly related to C++, but understanding this will be helpful to understand how C++ works.)

More-or-less, everything needs to be loaded into registers. Most computers are organized around a datapath, a bus connecting the registers, the arithmetic circuits, and the top level of the memory hierarchy. Usually, anything that is broadcast on the datapath is identified with a register.

You may recall the great RISC vs CISC debate. One of the key points was that a computer design can be much simpler if the memory is not allowed to connect directly to the arithmetic circuits.

In modern computers, there are architectural registers, which are a programming construct like a variable, and physical registers, which are actual circuits. The compiler does a lot of heavy lifting to keep track of physical registers while generating a program in terms of architectural registers. For a CISC instruction set like x86, this may involve generating instructions that send operands in memory directly to arithmetic operations. But behind the scenes, it's registers all the way down.

Bottom line: Just let the compiler do its thing.

  1. I think f() is a function in a way the same as g(x, y, z) is a function. How come x, y, z before calling g() are in the registers, and the parameters passed in g() are on the stack?

Each platform defines a way for C functions to call each other. Passing parameters in registers is more efficient. But, there are trade-offs and the total number of registers is limited. Older ABIs more often sacrificed efficiency for simplicity, and put them all on the stack.

Bottom line: The example is arbitrarily assuming a naive ABI.

  1. How is it known that the declarations for x, y, z make them stored in the registers? Where the data inside g() is stored, register or stack?

The compiler tends to prefer to use registers for more frequently accessed values. Nothing in the example requires the use of the stack. However, less frequently accessed values will be placed on the stack to make more registers available.

Only when you take the address of a variable, such as by &x or passing by reference, and that address escapes the inliner, is the compiler required use memory and not registers.

Bottom line: Avoid taking addresses and passing/storing them willy-nilly.

like image 100
Potatoswatter Avatar answered Sep 22 '22 04:09

Potatoswatter