chris@mimsy.UUCP (Chris Torek) (07/04/87)
(Reading news when I should be sleeping . . . :) In article <1213@carthage.swatsun.UUCP> rice@swatsun (Dan Rice) writes: >... Suppose I have defined structures containing other structures, i.e., > >typedef struct { > float x, y, z; /* Coordinates of a vector in 3-space */ >} vector; > >typedef struct { > vector o; /* Center */ > float r; /* Radius */ >} sphere; > >sphere s1, *s2; > >Now, say I refer to s1.o.x and s2->o.y. Does the compiler convert this into >a simple address reference at compile time, or is work performed at runtime? Clearly this is compiler dependent. A good compiler will do this as efficently as possible on your machine. That said, however, there are a few general rules. Global and static variables have addresses that are fixed at compile time (more precisely, at link time, but the compiler is dealing with `constants'). The offsets of members of structures within structures simply add, and this too is a compile time constant. Hence `s1.o.x' is `(address of s1) + (offset of o) + (offset of x)', which is the same value as `address of s1' (since the last two are [probably] zero). Since this is a compile (link) time constant, the compiler should simply access the float called `s1.o.x'. On a purely hypothetical machine called a Vax :-) this is, e.g., addf2 L16,_s1 Automatic (stack) variables do not have fixed addresses. The rest of the computation is the same, but `address of s1' is computed as `stack (frame) pointer plus offset to s1'. On our hypothetical Vax this is addf2 L16,-24(fp) which is still one instruction, although possibly slightly slower. Given enough stack data, this might become addf2 L16,-480(fp) which may be slower still, because the offset -480(fp) is encoded in two bytes, while -24(fp) is encoded in one. The actual timings depend not only on the Vax model but also on the alignment of the particular instruction and the contents of the cache and other uncertainties. Finally, pointer following can often be done only if the pointer's value is in a register. `s2->o.y' means `(value of s2) + (offset of o) + (offset of y)' or (Vax) `(value of s2) + 4'. This becomes either movl _s2,r0 addf2 L16,4(r0) (if, e.g., s2 is global), or movl -8(fp),r0 addf2 L16,4(r0) (for automatic s2) or addf2 L16,4(r10) (for `register struct sphere *s2'). >Should I define > >vector center; > >center = s2->o; > >if I plan to use s2->o several times? If `s2' is in a register, and `center' is automatic, this will probably make no difference. If both are automatic, or if s2 is global or static, this may help. But the only way to find out for certain is to try it, either timing the program or looking at the generated code. This sort of micro-tuning is best done after making the program work and *profiling*. You may be able to cut a three hour run to two hours with careful tuning, but only if you work on the code that takes that extra hour. Tuning code that does not run often does not make much difference. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris