Theoretically they can be but I don't know how safe it would be to use it or whether it will be a register or not. Registers are only used if the compiler does not run out of registers. You may code something as a register variable but the compiler doesn't have to generate the code as a register variable if it runs out of register variables. Also, I don't know if you can have global register variables.
A global register variable would make no sense, because the chances of that register remaining unused from one function to another are extremely slim. Almost by definition registers are very local things.
My feeling is that register variables are likely only to be useful in very small, tight bits of loopy code, and only to programmers who know the compiler and what it produces inside out. The chances are that in the right sort of loopy code the compiler will do a fairly good job anyway, and if it's that critical you may need to consider inline assembly.
I guess that the PC (program counter) could be considered as a volatile value (i.e. it changes constantly, so when using it, the program always needs to fetch the latest value). I cannot think of any other volatile registers right now (except those with similar properties as the PC), but when using address registers, their contents could be volatile also (e.g. when pointing to the data register of a serial chip).
Volatile does not neccesarily mean that the value of a varialbes changes. It only instructs the compiler to not optimize the code using the variable. So the compiler can not optimize by keeping its value in a register. The compiler generates code which always store the variable in memory if a value is assigned to it and which reads from memory if variable is read. Hence it makes no sense to apply additionally register to this variable. One main use for volatile is for values that may be changed by another task or thread (or even another CPU if they have common memory space).
Register is an aid for the compiler meaning: try to put this varialbe in register. But the compiler may ignore this at all, heavily depending on your code.
On the other hand, the interpretation of register and volatile as "variable is kept in register" and "variable content may change" is an interestring interpretation. For example, in microcontrollers you have memory mapped registers, which indeed may change. But they are already in memory...
What I do not understand is the example from PieterWinter with address registers. Why should those be volatile? Who changes them? If you mean pointer arithmetic, then the compiler knows those changes. No one else should change your pointer, hence they should not be volatile. Same goes with PC. The compiler should know how the PC evolves over time (interrupts have to be handeld by architecture). An instruction has an implicit increment of PC or an assign to PC, if it is an branch or loop. But no onw else will (or should) change the PC of our task from outside.
My example "when using address registers, their contents could be volatile also (e.g. when pointing to the data register of a serial chip", the "contents" that I referred to are not that of the register itself, but of the data it points to.
Some registers of a CPU are used for data, some for address pointers (it may be that a register can be used bothways, depends on the CPU). E.g. PC is typically an address register (with very specific properties).
The contents bit that I referred to was not that of the address register itself, but the location it points to. The address itself does not have to be fetched each time (can be left in register if optimisation permits). The value it points to needs to be fetched each time: cannot be optimized.
thank you for your clarification. Now I fully agree with you.
I misinterpreted your description. For me the content (or value) of an address register is the address it points to, but this might be wrong due to a lack of my experience in english. What is the right terminology for the addres registers value and the value it points to?
ermmm.... yes, I think that's clear.
Just a comment though:
I sort of feel that the only "register" variables that make sense on a PC are those relating to the eax, ebx, ecx, edx registers, (or the working space of the maths coprocessor side of things?). Yes, you can point something like es:di at a memory-addressed chip so the contents of es:[di] change without the processor doing anything, but from the point of view of the processor, something held in es:[di] is not a register variable: it's a perfectly ordinary (albeit volatile) bit of memory. Its addressing is no different to any variable held in heap space.
Presumeably the idea of register variables is that by holding the value in the processor in a register, you save a bit of time in interaction with the cache (or worse, real memory). Simple things like add, mov etc. eax, something (RISC-like) are capable of running simultaneously in two pipelines and only take a single cycle if all is going well (Sorry, my understanding drops off with pentium 3). Once you start doing things that use memory directly, but not a "normal" register, the instructions stop being risc-like and take multi-cycles.
Thanks for interesting thread.
the modifier register is only an hint for the compiler to try to keep a variables content in an register during its liftime. Which registers are used for variable values depends highly on architecture and even compiler. E.g. a compilers vendor could use only two register to perfom all neccesarry operations (thoug the resulting code would be quite slow).
Compilers use a technic, called register colouring, to map variables lifetime to available registers. If the compiler runs out of registers he has to do some spilling (save variable content to memory and reload it later into an register, not neccessarily the same as before). Now, if you have some variable that is used heavily or in a loop that should be as fast as possible, you could try to instruct the compiler to keep this variable in register in favour of another variable, that normal compiler optimization and register colouring would use.
IMHO the only variable where register makes sense are those which are used very often in time critical code sections and only for variables which are local.
microcrontrollers have a special region of memory (special addresses), into which some registers are mapped. This means, if you access this address with a move instruction, you do not access RAM (or ROM), but you in fact access an register of the CPU. Thus you can not have useful RAM at those addresses.
To understand the reason for this one must know a little bit about the encoding of instructions. So I try to give you a short scetch:
An assembly instruction is translated into opcode (a binary value, that can be read by CPU). This value has to contain at least information about the operation and its operands. So we have to reserve some bits for the operation and some for the operands. Many instructions have three operand, e.g. the addition with
ADD operand 1, operand 2, operand 2
where operands 1 is destination and op 2 and op 2 are source.
Now suppose we have 8 general purpose registers: r1-r7. To address them we need 3 bits. We also want to be able to access memory instead of registers. We can select this by using another bit per operand. This bit will note the CPU that the operand address immediatly follows the opcode. (We can code more than this with 4 bits, e.g. selecting one of 8 page registers).
Now what if we have to address 256 different registers? Yeah, the opcode would become quite large, because we would have to spend 8 bits per operand into opcode, and this would hold for most instructions. Therefore we code only our general purpose registers directly into opcode and try to access the others by use of memory addesses. We lose only 256 memory elements, which is small compared to normal memory size.
Now, what has this to do with compiler? From the compilers point of view it does not matter wheter these registers are stored in external memory or if they are mapped. You can define a pointer into the memory area of special function register and by this accually access an CPU's internal register. The compiler can not tell...
Thanks fro.
Yes, I agree, register variables only useful for very time-critical code in small loops.
But frankly I'm dubious about register variables at all, because I think probably most optimising compilers nowadays will do a better job of register allocation than the average programmer, especially bearing in mind that the C programmer probably doesn't know much about what his code turns into (she/he doesn't want to: they've got enough on their plate getting the C code right. What would be the point of a compiler if you had to spend all your life worrying about what it was doing??).
On the odd occasion that a loop really is that time critical, my inclination is to go the whole hog and burst into inline assembly. Register variables are a bit of a halfway house.
Having said that, I suppose register variables are still cross-platform compatible, which inline assembly isn't, and there may be some algorithm out there where it is so unobvious which variables are most highly used that the compiler needs a bit of assistance.
youp, you are right, but we must not forget that not all compilers have equally well designed optimization techniques buildin. With those compilers you are happy to give him some hints. This is espassially true for C, because C is not a pretty languge, but it gives you control over generated code near assembly with advantage from structured programming. An example for additional hints that you can give the compiler is pre- and postincrement. You can write
a = a + 1;
or
a++;
which are equivalent. But suppose the compiler does not notice this equivalence, he could generate for the first
move r1,@a
move r2,1
add r1,r2
move @a,r1
and for the second
inc @a
(I truly know of an architecture capable of incrementing memory values directly).
IMHO a programmer, which does not worry about what a compiler does, should not program at all. This might be a very harsh point of view, but if you have to deal with microcontrollers and DPS's, then you have to now about the last bit that is changes (no joke!). This view might, of course, not hold for WinDOSE or GUI applications, but evben there it would be wise to have a good understanding of what a compiler generates.
Now to optimizing using inline assembly: ther are some types of code, which are done best in assembly. E.g. if you write an OS and you develop context switch, then you will have to write parts of it in assembly. Thera are other examples, e.g. special features of your architecture, that you can not access otherwise. But beware, keep assemlby code to an absolute neccessary minimum. This is why we have higher level languages, because maintaining assembly is a pain.
I personally like to know what the compiler is getting up to, because that's the sort of person I am. Sometimes I feel a bit out on a limb in these days of ever increasing complexity in higher-level languages, where it simply isn't trendy to ask what's going on behind the scenes.
Actually walking home last night (bicycle flat) it occured to me the definition of register variables in C is a bit half-hearted. The syntax should have included an option on stating the order of priority (so you'd write register(1), register(2) and so on, or something more appropriate but meaning the same).
This way the compiler would know which variables it should try hardest to keep in registers, and which to let slip when it runs out of register space.
As things are, the programmer is a bit stuck. If she/he defines too many register variables the compiler will simply write the code it would have anyway, giving up on what was requested. (Or worse still, it might write bad code keeping the first register variable it came across in a register, to the detriment of later variables that it might have optimised had it had a chance....) If the programmer doesn't define any register variables, the compiler will simply optimise to the level it was written to achieve.
In between, there is an "optimal" number of register variables to define, a number that depends on how many registers the processor has, and probably on surrounding code.
Thus how you use "register" probably ought to vary with platform... which is bad. A prioritised register definition would overcome this. But it's hardly a major weakness in C.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.