12

I have something like this

register unsigned int a, b, c;
int n;
for (n = 0; n < 10; ++n){
c = a + b
b = a
a = c
array[n] = c;
}

what it does, it doesn't matter. The code runs quickly the way it is now, slower if the register keyword is removed. However, when I add in register before int n, it actually runs slower than now, but faster than if no registers is used.

Can someone explain this to me? Thanks.

D.C.
  • 15,340
  • 19
  • 71
  • 102
SuperString
  • 21,593
  • 37
  • 91
  • 122
  • 3
    How many general-purpose registers does the target architecture have? Also, what compiler? – Anon. Jan 15 '10 at 00:57
  • 3
    Are you compiling with full optimizations enabled (eg `-O3`)? Most of the compiler's optimizations, including register allocation, are disabled by default. That makes any timings on debug builds ( compiled without some variant on `-O`) quite meaningless. – Crashworks Jan 15 '10 at 01:14
  • 2
    One possibility for example is that (with enough optimisation flags) your compiler would prefer to optimise n away entirely and instead loop by advancing a pointer representing `array+n`. Perhaps it pays attention to your `register` keyword, puts n in a register and (hence) doesn't make the optimisation it wants to. *But* what it does kind of matters - (1) it's generating Fibonacci numbers, so it's a small loop, so I'd be suspicious of any timings. (2) a and b aren't initialised, so the optimiser could basically do what it likes with this and (hence) produce unfeasibly fast, broken code. – Steve Jessop Jan 15 '10 at 01:17
  • Oh, and the reason for the `array+n` being faster, if indeed it is, could be to do with addressing modes or could be because it uses one less register that way, and if you force the extra register you get a stack spill in the loop. Some such thing, anyway - this code is simple enough that if you just look at the disassembly for the two different versions, you might well be able to see why the slower one is slower. – Steve Jessop Jan 15 '10 at 01:20

6 Answers6

20

How did you time this? In practice, register usually does nothing. It's a piece of cruft from when compiler technology was extremely primitive and compilers couldn't figure out register allocation themselves. It was supposed to be a hint to allocate a register to that variable and was useful for variables used very frequently. Nowadays, most compilers simply ignore it and allocate registers according to their own algorithms.

dsimcha
  • 67,514
  • 53
  • 213
  • 334
  • 3
    I've heard many places that this flag is ignored, but I've never seen anything to back this up other than rumor. Do you happen to have sources? In my experience with gcc this flag can sometimes make a difference (though I admit that difference is usually negative). – SoapBox Jan 15 '10 at 01:01
  • @soap dsimcha is right, it is a relic of times gone by. wiki it google it etc -- you will find your proof. – Hassan Syed Jan 15 '10 at 01:07
  • but the fact is that I calculated the time and I am getting the result like I said in the problem – SuperString Jan 15 '10 at 01:10
  • How did you "calcuate" the time? Can you post the generated assembly for each version? – Anon. Jan 15 '10 at 01:11
  • 5
    It makes a difference in gcc when optimisations are turned off (reference: http://gcc.gnu.org/onlinedocs/gcc/Hints-implementation.html). – Matthew Slattery Jan 15 '10 at 01:18
  • 2
    Though one would wonder why you're trying to "optimize" with `register` when you're compiling without optimizations. – Anon. Jan 15 '10 at 01:22
  • 1
    It is deprecated in C++0x, oops, 1x: http://www-949.ibm.com/software/rational/cafe/blogs/cpp-standard/2009/11/06/to-derprecate-or-not-deprecate-that-is-the-question – Hans Passant Jan 15 '10 at 01:52
15

register gives the compiler a hint to place the variable in a register instead of memory/stack space. In some cases, there won't be enough registers for every variable you place this keyword on so placing it on too many variables can force some of the others out of registers again.

This is just a hint, though, and the compiler doesn't have to take it.

SoapBox
  • 20,457
  • 3
  • 51
  • 87
  • 1
    It also means you can't pass the variable by address - or shouldn't do so because a variable in a register has no address. – Jonathan Leffler Jan 15 '10 at 01:33
  • 2
    Passing a `register` variable by address simply tells the compiler to spill it to stack. It's quite legal in C++ (but not ANSI C). – Crashworks Jan 15 '10 at 18:42
  • Please note that sometimes, there are not enough registers available on chip. You just `request` program to use register. It may not use it. – ahmet alp balkan May 14 '11 at 21:30
6

In gcc, register is definitely not ignored, unless you specify optimization options. Testing your code with something like this

unsigned int array[10];

int n;

#define REG register

int main()
{
    REG unsigned int a, b, c;

    for (n = 0; n < 10; ++n){
        c = a + b;
        b = a;
        a = c;
        array[n] = c;
    }
}

you obtain (depending on whether REG is defined or empty)

diff http://picasaweb.google.com/lh/photo/v2hBpl6D-soIdBXUOmAeMw?feat=directlink

On the left is shown the result of using registers.

elp
  • 8,021
  • 7
  • 61
  • 120
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
1

There are a limited number of registers available, so marking everything as register won't put everything in registers. Benchmarking is the only way to know if it's going to help or not. A good compiler should be able to figure out what variables to put into registers on its own, so you should probably benchmark some more before you decide that the register keywords helps.

Amok
  • 1,279
  • 9
  • 10
  • "Benchmarking is the only way to know if it's going to help or not". Well, he says he has benchmarked, and that he's come up with results for three different cases. If his benchmarks are incorrect, then telling him to benchmark again won't make them correct ;-) – Steve Jessop Jan 15 '10 at 01:23
  • It seems strange that there would be a difference since an optimizing compiler should know which variables should go into registers, so I think it's wise to benchmark again to make sure it's done right. – Amok Jan 15 '10 at 02:24
1

The idea of using register is, your variable is used extremely often. If there is any operation with your variable, it will be copied to a register anyway. So counter (index variables) are candidates for this modifier. In the example of Diego Torres Milano from Jan 15 '10 at 1:57 I would make it this way:

unsigned int array[10];    

int main()
{
    register int n;
    unsigned int a = 1, b = 2, c;

    for (n = 0; n < 10; ++n){
        c = a + b;
        b = a;
        a = c;
        array[n] = c;
    }
}
mdarge
  • 11
  • 3
-1

There's a limit to allocatable registers. If you outgo it, you just end up with less efficient code.

My take is that if what you do is so important that you have to decide yourself what goes in a register and what doesn't, you should write it using assembly language.

For general purpose languages, I strongly believe that a compiler is better able to decide what goes in a register than a human. The proof being that while you're not sure how many variables you can put in registers, your compiler knows for sure.

zneak
  • 134,922
  • 42
  • 253
  • 328