3

As I'm not too much familiar with cpu registers, in general and in any architecture specially x86 and if compiler-relevant using VC++ I'm curious that is it possible for all elements of an array with a tiny number of elements like an array of 1-byte characters with 4 elements to reside in some cpu register as I know this could be true for single primitives like double, integer, etc ?

when we have a parameter like below:

void someFunc(char charArray[4]){
//whatever
}

Will this parameter passing be definitely done through passing a pointer to the function or that array would be residing in some cpu register eliminating the need to pass a pointer to main memory?

Pooria
  • 2,017
  • 1
  • 19
  • 37
  • As you mentioned, this is very platform and compiler specific. Please provide some specs. – Björn Pollex Nov 08 '10 at 10:20
  • It would depend on the size of the CPU registers, it it's a 32bit int and it is a 32bit CPU, only 1 variable of your array can fit, I doubt that an array in its whole will ever be put inside a CPU register, at most a pointer to some element in an array I would think. – Tony The Lion Nov 08 '10 at 10:25

6 Answers6

5

This is not compiler dependent, nor is it possible. Arrays cannot be passed by value in the same way as other types, i.e. they cannot be copied when passed into a function. The C++ standard is clear in that when processing a function signature in a declaration the following are exact equivalencies:

void foo( char *a );
void foo( char a[] );
void foo( char a[4] );
void foo( char a[ 100000 ] );

A compliant compiler will convert the array in the function signature into a pointer. Now, at the place of call, a similar operation takes place: if the argument is an array, the compiler has to decay it into a pointer to the first element. Again, the size of the array is lost in the decay.

Specific registers can be used to hold more than one value and perform operations on them (google for vectorized operations, MME and variants). But while that means that the compiler can actually insert the contents of a small array into a single register, that cannot be used to change the function call that you refer to.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    That's two in one day (http://stackoverflow.com/questions/4120658/). Someone should probably track down a really good answer to all this stuff and tag it c++-faq. – Steve Jessop Nov 08 '10 at 11:29
  • Will this prevent the same optimization if a function call is eliminated thanks to inlining? – sharptooth Nov 08 '10 at 11:30
  • @Steve Jessop: While the answer is the same, I can understand the user not recognizing that the two questions are exactly the same: what the concrete semantics of the "pass-by-value" syntax is for arrays. – David Rodríguez - dribeas Nov 08 '10 at 11:32
  • 1
    @Sharptooth, if the function is inlined, the compiler will operate directly in the array, because it is able to do it while still fulfilling the *as-if* guarantee. But again, this does not mean that the array can be passed in a register, it is not passed at all. Passing the array in registers would have the side effect that operations that potentially modified the array inside the function would only modify the registers, and not the real memory, and that is a breaking change in the semantics. – David Rodríguez - dribeas Nov 08 '10 at 11:35
  • @dribeas: yes, sorry, I didn't mean this question was the same. Actually this one is specifically about function parameters, and the other one is specifically about objects. I just meant that it has also invoked "arrays are pointers" wrongness among the answers, and nobody countering that wrongness has done so just by producing a "this is why you're wrong" FAQ. – Steve Jessop Nov 08 '10 at 12:06
4

Within a single function, an array could be held in one or more registers, just so long as the compiler is able to produce CPU instructions to manipulate it as the code dictates. The standard doesn't really define what it means for something to "be" in a register. It's a private matter between the compiler and the debugger, and there may be a fine line between something being in a register, and being "optimized away" entirely.

In your example, the parameter is a pointer, not an array (see dribeas' answer). So it would be unusual that the array it points to could possibly be held a register. The "main" architectures that you probably deal with don't allow a pointer to a register, so even if the array was held in a register in the calling code, it would have to be written into memory in order to take a pointer to it, to pass to the callee.

If the function call was inlined, then better optimizations might be possible, just as if there were no call at all.

If you wrap your array in a struct, then you turn it into something that can be passed by value:

struct Foo {
    char a[4];
};

void FooFunc(Foo f) {
    // whatever
}

Now, the function is taking the actual array data as its parameter, so there's one less barrier to holding it in a register. Whether the implementation's calling convention actually does pass small structs in registers is another question, though. I don't know what calling conventions do this, if any.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

Out of the 5 or so compilers I'm fairly familiar with, (Borland/Turbo C/C++ from 1.0, Watcom C/C++ from v8.0, MSC from 5.0, IBM Visual Age C/C++, gcc of various versions on DOS, Linux and Windows) I've not seen this optimization happen naturally.

There was a string library, whose name I cannot remember, that did optimizations similar to this in x86 ASM. It may have been part of the "Spontaneous Assembly" library, but no guarantees.

JimR
  • 15,513
  • 2
  • 20
  • 26
1

A function that accepts an array is probably going to index into that array. I know of no architecture that supports efficient indexing into a register, so it's probably pointless to pass arrays in registers.

(On an x86 architecture, you could access a[0] and a[1] by accessing al and ah of the eax register, but that is a special case that only works if the indexes are known at compile time.)

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • e.g. the 8051 has addresses in the memory map corresponding to registers. Indexed access to those addresses is the same or better than indexed access to any other memory, *but* of course you'd have to use multiple registers for an array any bigger than 1, so if you did it then your array wouldn't be held in "some CPU register". Rather, "some CPU registers". – Steve Jessop Nov 08 '10 at 12:01
  • As long as the compiler can determine all of the indices at compile-time, they can be replaced with register references. – einpoklum Apr 22 '15 at 21:36
0

You asked if its possible with VC++ on an x86.

I doubt it's possible in that configuration. True, you could produce assembler code where that array is kept in a register, but due to the nature of arrays it would be by no means a natural optimization for a compiler, so I doubt they put it in.

You can try it out though and produce some code where the compiler would have an "incentive" to put it in a register, but it would look pretty weird like

char x[4];
*((int*)x) = 36587467;

Compile that with optimizations and the /FA switch and look at the assembler code produced (and then tell us the results :-))

If you use it in a more "natural" way, like accessing single characters or initializing it with a string there is no reason at all for the compiler to put that array into a register.

Even when passing it to a function - the compiler might put the address of the array into the register, but not the array itself

TToni
  • 9,145
  • 1
  • 28
  • 42
-1

Only variables can be stored in a register. You can try to force register storage by using the register keyword: register int i;

Arrays are by default pointers.

You can get the value located at the 4 position like this (using pointer syntax):

char c = *(charArray + 4);
Liviu Mandras
  • 6,540
  • 2
  • 41
  • 65
  • 2
    Eh, modern C++ compilers will ignore the `register` keyword. If the optimizer figures out that a variable would benefit from register storage, it will be used accordingly. *Regardless* of whether it was declared as `register`. – Konrad Rudolph Nov 08 '10 at 10:31
  • 1
    Not again... arrays are **not** pointers, they **decay** into pointers easily (whenever used as a rvalue), but they are not pointers. – David Rodríguez - dribeas Nov 08 '10 at 11:20
  • dribeas is right. It's further complicated by the fact that arrays can't be passed by value, so array-looking parameters are actually pointer parameters. – Steve Jessop Nov 08 '10 at 11:30