stevens (03/28/83)
Until a few years ago Yourdon, Inc. was in the C compiler business. I am aware of a compiler they sold for the PDP-11 (Unix and RSX-11 versions) and they also developed one for IBM for their Series/1 (under the EDX operating system, I believe - IBM never released it since they changed the OS under Yourdon's feet during developement and when the compiler was completed it wouldn't work under the new version of EDX!). Anyway, Yourdon's PDP-11 compiler allowed longs to be assigned to two of the three available registers on the PDP-11 and also allowed floats and doubles to be assigned to two of the 4 FP registers. I consider that quite amazing since the Ritchie compiler, PCC and Whitesmiths don't go that far with register variables on the 11. PCC on the VAX doesn't even allow floats or doubles in registers either. Is anyone aware of any other C compilers that allow either floats/doubles to be assigned to registers or allow multi-register register assignments (longs on the PDP-11, for example)? Richard Stevens ...decvax!kpno!stevens ...ucbvax!arizona!kpno!stevens
shekita@crystal.UUCP (06/20/85)
I have some questions about register variables: 1) When is it appropriate to declare a variable as a register? I have been told that declaring a variable as a register can actually result in slower code. Is there a rule of thumb dictating when and when not to declare a variable as a register? 2) How many variables can be declared as registers on a Vax 780? In general, is there some way to tell how many register variables can be declared? Eugene Shekita Univ of Wisconsin
chris@umcp-cs.UUCP (Chris Torek) (06/21/85)
> From: shekita@crystal.UUCP > When is it appropriate to declare a variable as a register? I have > been told that declaring a variable as a register can actually > result in slower code. Is there a rule of thumb dictating when and > when not to declare a variable as a register? Declare things registers when they're heavily used. You *can* make code run slower; consider how long it takes to save and restore the register(s) before using them for something trivial. > How many variables can be declared as registers on a Vax 780? In > general, is there some way to tell how many register variables can > be declared? Depends on the compiler. Most Unix compilers have 6 registers on Vaxen (r11-r6). VMS uses r12-r2 (!), though I don't know how their compiler reacts to register declarations. Sun's C compiler has 4 register pointers (a5-a2) and 6 register integers (d7-d2). (I think.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
faustus@ucbcad.UUCP (Wayne A. Christopher) (06/22/85)
Speaking of register variables -- does anybody know what various C compilers do when you don't declare variables as register, but there are spare registers to use? From what I hear, neither ccom nor c2 are smart enough to put local variables in registers when they are available. It seems that it would be simple to just take the first few, or even the most heavily used local variables that don't ever get &'d and make them register... Wayne
arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (06/22/85)
In article <472@crystal.UUCP> shekita@crystal.UUCP writes: >1) When is it appropriate to declare a variable as a > register? I have been told that declaring a variable > as a register can actually result in slower code. Is > there a rule of thumb dictating when and when not to > declare a variable as a register? Generally, the only time declaring a variable to be a register generates slower code is when you declare a parameter to be a register. This is because, on most systems, this requires a move from the stack into a register. If the variable is rarely used, this overhead may cost you more than having it in the register saves. In some degenerate, unpredictable cases a compiler which isn't properly written will generate worse code for a register variable than a non-register variable. I have seen this happen once on a vax. However, you have no way of prediciting this kind of behavior, and since someone might fix the compiler, you run a chance of getting worse code in the future. Some particularly smart compilers will use unused registers for storage of intermediate values to avoid recalculating them. Then you can hurt yourself by declaring rarely used variables, since it takes them out of contention for this, but these compilers are VERY rare. >2) How many variables can be declared as registers on a Vax 780? > In general, is there some way to tell how many register variables > can be declared? You have an infinite number of registers. No, seriously, this is the way to think about it. You should declare EVERYTHING which you don't have to take the address of to be a register. You can tell old pdp-11 code in UNIX by the fact that they leave off declaraing register variables after three. Then, when the code was brought to a vax, which has five, this potential optimization was lost. If you declare all legal variables to be registers, your code ports and takes advantage of the new machine's resources without added work. By EVERYTHING I mean just that. Some machines have floating point registers and some don't. Some don't put chars in registers and others do. Some don't put in shorts in. Some put one-word structures in registers. Some will someday put multiword structures in registers, if somebody doesn't already. Just be somewhat careful to declare things in the order you care about. This cuts both ways -- if you move to a machine with fewer registers than yours, you can loose the most critical register uses in favor of less critical. For example, let's posit a two register machine and the following code register int i, j; for (i = 0; ...) for (j = 0; ...) Now, move it to a one register machine, and "j", which is the most tested variable, is out of a register and "i", which is used less often, is still in one. Not what you want. All this shows is that register allocation should be done by the compiler, not the user, except in rare circumstances. Until someone does a C compiler this way, though, you're stuck with these techniques. Ken Arnold
chris@umcp-cs.UUCP (Chris Torek) (06/24/85)
Ken Arnold makes a good point here: > You have an infinite number of registers. No, seriously, this is the > way to think about it. You should declare EVERYTHING which you don't > have to take the address of to be a register. [...] Just be somewhat > careful to declare things in the order you care about. I have to admit to getting into the sloppy habit of stopping after six register declarations. But that's not why I'm writing this. . . what I really want to do is make another point here, and that is that you should declare register variables before ordinary variables (in general), since some machines (Pyramids) ignore the word ``register'' and just put the first N (12) variables in registers. (Such a machine must, of course, be able to take the address of a register.) Also (last point---I promise!), to C compiler writers: please don't parse the list of declarations and then perform the declarations in reverse order! -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
alex@ucla-cs.UUCP (06/24/85)
>Just be somewhat careful to declare things in the order you care >about. This cuts both ways -- if you move to a machine with fewer >registers than yours, you can loose the most critical register uses in >favor of less critical. For example, let's posit a two register >machine and the following code > > register int i, j; > > for (i = 0; ...) > for (j = 0; ...) > >Now, move it to a one register machine, and "j", which is the most >tested variable, is out of a register and "i", which is used less >often, is still in one. Not what you want. You are assuming the compiler assigns register variables in the order they are declared, which is not always true. An alternative solution is to do something like this: #define REG1 register #define REG2 register ... #define REG8 register /* assume 8 registers on our machine */ #define REG9 ... #define REG20 /* but up to 20 variables that might */ /* be put into registers */ Then declare the local variables as REG1 int j; /* j is most important */ REG2 int i; /* i is next most important */ ... The register #defines can go in a header file that uses #ifdefs to do the #defines appropriately for the machine you are using. This method makes it clear which variables are important to be placed in registers and which aren't. Alex
stew@harvard.ARPA (Stew Rubenstein) (06/26/85)
> In article <472@crystal.UUCP> shekita@crystal.UUCP writes: > >1) When is it appropriate to declare a variable as a > > register? I have been told that declaring a variable > > as a register can actually result in slower code. Is > > there a rule of thumb dictating when and when not to > > declare a variable as a register? > > Generally, the only time declaring a variable to be a register > generates slower code is when you declare a parameter to be a > register. This is because, on most systems, this requires a move from > the stack into a register. If the variable is rarely used, this > overhead may cost you more than having it in the register saves. This is not always true. On many (most?) systems, the use of a register in a subroutine requires that the register be saved before use and restored before return. So you get: Move register onto stack If a parameter or initialized auto then move initial value into register Do your subroutine Move saved value back into register On the vax, the register is saved and restored by the CALL instruction, but it still takes time.
jmoore@mips.UUCP (Jim Moore) (06/26/85)
> You have an infinite number of registers. No, seriously, this is the > way to think about it. You should declare EVERYTHING which you don't > have to take the address of to be a register. [...] Just be somewhat > careful to declare things in the order you care about. This is the method I always use in the procedures I write. I am accustomed to programming a 68k based machine and it does not take many references to a variable to justify any additional cost in making it a register on that architecture. Using this declaration method seems to be saying that the register hint given the compiler contains no information (other than promising not to take its address). What I really want is for the compiler to assign as many variables to registers as it can. I would also like it to assign to "right" variables to registers, including globals. In this scenerio, register declarations should act as over-rides to the compilers register allocation policy. This would result in code with fewer register declarations, but with more information contained in each one. Jim Moore MIPS Computer Systems Mountain View, CA ucbvax!decwrl!mips!jmoore
braun@drivax.UUCP (Karl Braun) (06/26/85)
Ken Arnold presented the following example while talking about the necessity of proper ordering when declaring register vars. > > register int i, j; > > for (i = 0; ...) > for (j = 0; ...) > It made me wonder if the following version would be any more efficient: register int i ; for( i = 0 ; ... ) { register int j ; for( j = 0 ;... ) } -- kral ihnp4!-------- \ mot! ---------- \ ucbvax!unisoft! > drivax!braun ucscc!--------- / amdahl!------- /
arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (06/27/85)
In article <6115@ucla-cs.ARPA> alex@ucla-cs.UUCP writes: >>Just be somewhat careful to declare things in the order you care >>about. This cuts both ways -- if you move to a machine with fewer >>registers than yours, you can loose the most critical register uses in >>favor of less critical. For example, let's posit a two register >>machine and the following code >> >> register int i, j; >> >> for (i = 0; ...) >> for (j = 0; ...) >> >>Now, move it to a one register machine, and "j", which is the most >>tested variable, is out of a register and "i", which is used less >>often, is still in one. Not what you want. > >You are assuming the compiler assigns register variables in the order >they are declared, which is not always true. It SHOULD always be true. If a compiler doesn't put things in registers in the order declared, it is not following (a) standard practice, or (b) K&R (the closest thing we currently have to a standard). K&R says A "register" declaration is best thought of as an "auto" declration, together with a hint to the compiler that the varibles declared will be heavily used. Only the first few such declarations are effective. "first few" means "first few". In the above listing, "i" comes before "j" and therefore is part of the "first few" before "j" is. Any compiler which puts "j" in first is doing it wrong. Ken Arnold
mhs@enmasse.UUCP (Mike Schloss) (06/27/85)
> Speaking of register variables -- does anybody know what various C > compilers do when you don't declare variables as register, but there > are spare registers to use? From what I hear, neither ccom nor c2 are > smart enough to put local variables in registers when they are > available. It seems that it would be simple to just take the first few, > or even the most heavily used local variables that don't ever get &'d > and make them register... > > Wayne Easier said than done. For example, what do you mean by most heavily used? Do you mean occurs most often in the code or encountered more often during execution. Assume two variables, one with 16 references in the first half of the routine and none in the second half, another variable with only one reference in the second half, in a loop, where the program spend 98% of its time. Get the picture? Also the is some cost to using registers, the overhead of storing and restoring them. A compiler does not know about execution paths so it can not deal with this properly. Better left to the programmer who shoud know better about variable usage and possible input data.
maxwell@speedy.DEC (06/28/85)
It's a shame that we're all too often hampered by the lack of good optimizing compilers. The only reason that K&R's C *has* register variables in the first place is because their original C compiler (and most later ones) can't generate reasonable code without (and often even with) them. These compilers require 'hints' about variable use. The trouble is, many compilers take the hint indiscriminatly, without regard for the program itself. (The variety of assignment operators are there for the same reason). The 'register' storage class qualifier should generally be *ignored* by a good compiler: the compiler should place values (and not just variables necessarily, but common subexpressions as well) in registers as it sees fit. E.g. a compiler can realize that a variable is used inside a loop and generate code accordingly, etc. Not to blow DEC's horn too loudly, but the VAX C compiler *is* a good compiler, at least by this definition. Declaring a variable 'register' increases the likelyhood of that variable getting a register (increases its priority); but generally the compiler keeps track of variable usage (up to 32 of them) and generates code according to their use. 'register' variables are otherwise treated *exactly* like regular 'auto' ones. For those who might be interested, the compiler technology used by the VAX C compiler is described in "Engineering a Compiler: VAX-11 Code Generation and Optimization", Digital Press. Perhaps PCC (et al) users should read books like this and rewrite a few compiler backends. -+- Sid "some of my best friends write compilers" Maxwell, DEC @ Spit Brook Rd, Nashua NH "I seriously doubt that the opinion, as expressed in the preceding message, is necessarily shared by anyone else, including my employer. So there."
pritch@osu-eddie.UUCP (Norman Pritchett) (06/30/85)
Just for the sake of information, VMS ignores register declarations and automatically decides for itself how frequently you use each variable and whether or not to make it a "register declaration". I personally don't think this is the wisest approach but after looking at a number of machine code listings it actually appears to work well under most conditions. > > From: shekita@crystal.UUCP > > > > How many variables can be declared as registers on a Vax 780? In > > general, is there some way to tell how many register variables can > > be declared? > > Depends on the compiler. Most Unix compilers have 6 registers on > Vaxen (r11-r6). VMS uses r12-r2 (!), though I don't know how their > compiler reacts to register declarations. Sun's C compiler has 4 > register pointers (a5-a2) and 6 register integers (d7-d2). (I think.) > -- > In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) > UUCP: seismo!umcp-cs!chris > CSNet: chris@umcp-cs ARPA: chris@maryland -- ----------------------------------- Norm Pritchett UUCP: cbosgd!osu-eddie!pritch CSNET: pritch@ohio-state BITNET: TS0017 at OHSTVMA MA-NET: (614) 291-8775
ps@celerity.UUCP (Pat Shanahan) (07/01/85)
> Speaking of register variables -- does anybody know what various C > compilers do when you don't declare variables as register, but there > are spare registers to use? From what I hear, neither ccom nor c2 are > smart enough to put local variables in registers when they are > available. It seems that it would be simple to just take the first few, > or even the most heavily used local variables that don't ever get &'d > and make them register... > > Wayne Release 2.1 of the Celerity C1200 C compiler implements simple automatic register allocation for optimized compiles. Declared register variables have priority for allocation of registers. The remaining registers are allocated for an arbitary selection of the simple automatic variables, excluding any that have their addresses calculated. Automatic register allocation is particularly important for the C1200, because it provides an unusually large number of registers and a wide range of types of register variables. The C1200 supports all integer types and both floating point types in registers. Depending on the number of registers that the function needs for arguments, up to 26 integer registers can be allocated. The C1200 also has 15 floating point registers, of which the C compiler will allocate up to 9 for variables. Each floating point register can contain either a float or a double. This large supply of registers is very desirable for big FORTRAN subroutines. The C compiler makes no attempt to do usage based allocation and allocates registers for the whole scope of the variables, since the number of registers exceeds the number of suitable variables in most C functions. For example, all suitable automatic variables in the C compiler first pass fit into registers. Excessive register allocation is not a concern on the C1200, because the architecture supports rapid saving and restoring of blocks of registers. The C1200 C compiler first pass user time improved by 5% due to automatic register allocation. This is probably typical of UNIX code that already has many register declarations, and that does not use floating point much. The largest improvement I have seen so far was in a small artificial benchmark. The user time reduced from 13.4 seconds to 8.6 seconds. Obviously, there would be no improvement in a program that already had all possible variables declared register. -- ps (Pat Shanahan) uucp : {decvax!ucbvax || ihnp4 || philabs}!sdcsvax!celerity!ps arpa : sdcsvax!celerity!ps@nosc
brooks@lll-crg.ARPA (Eugene D. Brooks III) (07/02/85)
> Just for the sake of information, VMS ignores register declarations and > automatically decides for itself how frequently you use each variable and > whether or not to make it a "register declaration". I personally don't > think this is the wisest approach but after looking at a number of machine > code listings it actually appears to work well under most conditions. The Tartan C compiler for vaxen seems to do equally well with register allocation for frequently used variables. I don't know if they pay any attention to register declarations. Forced register declarations are useful in their own right. Sometimes its its quite convenient to use register declarations and asm statements here and there to cheat the compiler. It certainly beats writing whole modules in assembler. YEA! I KNOW! All you people out there in netland are saying "GAG ME WITH A SPOON!" For sure, for sure.
brent@cadovax.UUCP (Brent Rector) (07/02/85)
In article <421@osu-eddie.UUCP> pritch@osu-eddie.UUCP (Norman Pritchett) writes: >Just for the sake of information, VMS ignores register declarations and >automatically decides for itself how frequently you use each variable and >whether or not to make it a "register declaration". I personally don't >think this is the wisest approach but after looking at a number of machine >code listings it actually appears to work well under most conditions. > >Norm Pritchett >UUCP: cbosgd!osu-eddie!pritch So what happens then if you are frequently referencing a memory mapped device register, will the VMS compiler cache the first reference in a register? (Note that I am aware of the proposed 'volatile' definition in the standard). Or can you tell the compiler to listen to register definitions in certain cases. -- -------------------------------------------------------------- Brent E. Rector - CONTEL CADO, Torrance, CA { decvax, hplabs, ihnp4, ucbvax, sdcrdcf }!trwrb!cadovax!brent philabs!cadovax!brent
eds@solar.UUCP (E.SCHULZ) (07/03/85)
In our current application, we are writing C code for an 8086-family processor in an embedded system. Our objective is to keep the ROM and RAM down, so that the components will fit on the board and will be low cost. We don't think that execution time is as important as keeping the ROM under 128K bytes. Given the above, I would prefer to have the compiler assign register variable(s) based on their static occurrence in the code. The references to memory take more code space than references to registers. Just another point of view... Ed Schulz AT&T-IS, Holmdel, NJ solar!eds (201)834-3838
rcd@opus.UUCP (Dick Dunn) (07/04/85)
> I have to admit to getting into the sloppy habit of stopping after > six register declarations. But that's not why I'm writing this. > . . what I really want to do is make another point here, and that > is that you should declare register variables before ordinary > variables (in general), since some machines (Pyramids) ignore the > word ``register'' and just put the first N (12) variables in > registers. (Such a machine must, of course, be able to take the > address of a register.) Sounds like the Pyramid compiler has a problem there, to the extent that it's not following the spirit of the `register' declaration. Who ever said that "order of declaration" is a hint to the compiler on which variables are most frequently used?! Also, it's not generally possible to declare register variables before ordinary variables--parameters are effectively just initialized local variables, but the syntax requires that they all be declared before any of the locals. The parameter-vs-local distinction is another reason that compilers ought not to do what the Pyramid compiler is described as doing. -- Dick Dunn {hao,ucbvax,allegra}!nbires!rcd (303)444-5710 x3086 ...A friend of the devil is a friend of mine.
chris@umcp-cs.UUCP (Chris Torek) (07/05/85)
> Sounds like the Pyramid compiler has a problem there, to the extent that > it's not following the spirit of the `register' declaration. It *is* kind of tacky. It works, though. > Also, it's not generally possible to declare register variables before > ordinary variables--parameters are effectively just initialized local > variables, but the syntax requires that they all be declared before any of > the locals. The parameter-vs-local distinction is another reason that > compilers ought not to do what the Pyramid compiler is described as doing. Actually, since on Pyramids the first 12 arguments to a procedure are already in registers (different from the 12 local registers) this doesn't matter. Again it just ignores the register declarations, this time because of the subroutine call architecture. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
stern@bnl.UUCP (eric) (07/07/85)
> In article <421@osu-eddie.UUCP> pritch@osu-eddie.UUCP (Norman Pritchett) writes: > >Just for the sake of information, VMS ignores register declarations and > >automatically decides for itself how frequently you use each variable and > >whether or not to make it a "register declaration". I personally don't > >think this is the wisest approach but after looking at a number of machine > >code listings it actually appears to work well under most conditions. > > > >Norm Pritchett > >UUCP: cbosgd!osu-eddie!pritch > > So what happens then if you are frequently referencing a memory mapped > device register, will the VMS compiler cache the first reference in a > register? (Note that I am aware of the proposed 'volatile' definition > in the standard). Or can you tell the compiler to listen to register > definitions in certain cases. > > -- > -------------------------------------------------------------- > Brent E. Rector - CONTEL CADO, Torrance, CA > { decvax, hplabs, ihnp4, ucbvax, sdcrdcf }!trwrb!cadovax!brent > philabs!cadovax!brent The VAX-11C compiler already supports volatile declarations, as well as variables defined in readonly storage. In addition, to avoid allocating program sections (of which there are a limited number), You can define entry points in your program, and reference entry points in other programs. This last feature is only of use under VMS, since the concept of external names is totally different between VMS and Unix. Eric Stern stern@bnl.arpa stern@bnl.bitnet stern@bnldag.bitnet (new) ...!philabs!sbcs!bnl!stern
stpeters@steinmetz.UUCP (R L StPeters) (07/09/85)
> The 'register' storage class qualifier should generally be *ignored* by a > good compiler: the compiler should place values (and not just variables > necessarily, but common subexpressions as well) in registers as it sees fit. > E.g. a compiler can realize that a variable is used inside a loop and > generate code accordingly, etc. Compilers that use register variables as they see fit can add much to the overhead of function calls due to large register masks. This was the only reason we could figure for a friend's program's execution time being about twice as long when compiled with the VAX-11 C compiler as when compiled with our Interactive Systems' IS/1 compiler (multiple comparison runs on the same 11/782/VMS system under the same average load conditions). His program spent much of its time calling several fairly large procedures isolated in a module. These were called thousands of times and usually simply returned after making one simple comparison, but occasionally they did something complex. This happened seldom enough so it mattered little whether they used register variables. The DEC-compiled version apparently spent an awful lot of time just saving and restoring unchanged registers. I don't know if he ever tested it using the /noptimize qualifier. He just went back to the IS/1 compiler. It ran fast enough. Personally, I have a problem with compilers that decide on their own that something I tell them should be *ignored*. The VAX-11 C compiler's optimization has made a number of my own procedures not work. But then I have a habit of doing in C things that a compiler-writer might think god intended to be done only in assembly language. -- R. L. St.Peters (Dick) The "R" is for "Reptile". uucp: decvax!mcnc!ncsu!uvacs!edison!steinmetz!stpeters (uucp is forever) arpa: stpeters@ge-crd (federal express) "Any opinions expressed by my employer are probably not mine."
atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (07/17/85)
The semantic meaning of a "register" declaration is NOT that the compiler must place the variable in a register. Instead if you stop to think it is really a declaration that this variable is never affected as a side effect of an indirect store (* or []), an so a copy of the variable in a register can still be believed. The "register" declaration should really only be interpreted in this sense, even though some compilers decide to always keep the first few such variables in registers. Compilers that do such are not in violation of this interpretation, but are taking an unneccessarily narrow interpretation, and as a result some times produce worse code since they lose the use of extra registers when they would be most useful. "register" is supposed to be an optimizing HINT, not suboptimal code requirement.
lcc.niket@UCLA-LOCUS.ARPA (Niket K. Patwardhan) (07/19/85)
>The semantic meaning of a "register" declaration is NOT that the compiler >must place the variable in a register. Instead if you stop to think >it is really a declaration that this variable is never affected as a >side effect of an indirect store (* or []), an so a copy of the variable >in a register can still be believed. The "register" declaration I never thought of it that way before, but you are right. Interesting...... using register declarations can make a C program much more provable!!!! :x