pardo@june.cs.washington.edu (David Keppel) (08/27/88)
TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: > f(i){ int tmp; i = i*i; tmp = 222; } > returns a value! This kicked my funny bone. look at the assembly output (or dissassembled output) of the compiler. You will see that: * function return values are always in the same register (e.g, r0) * temporary calculations are made using the same register thus * the "correct" value winds up in the return value accidentally. The reason this kicked my funny bone is that at times there has been code that *relied* on this behavior and I have seen at least one style guide that says "don't depend on this behavior". Gcc (GNU C compiler) is smart enough (on a VAX, anyway) to perform temporary computations in the return register, avoiding extra copies, while pcc (which, in all fairness, is many years older) will occasionally produce code as shown below, even with the optmizer turned on (not for the above code, though, it does other entertaining things): cvtbl -4(fp),r0 movl r0,r0 # Could be optimized to "nop" :-> ret This is all because of a "phase ordering problem", that you can't select register use until you know what instructions you're trying to use and you can't select optimal instructions until you know what registers you have to play with. ;-D on ( More fun than a barrel of cats ) Pardo -- pardo@cs.washington.edu {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo
chris@mimsy.UUCP (Chris Torek) (08/27/88)
In article <5571@june.cs.washington.edu> pardo@june.cs.washington.edu (David Keppel) writes: >... pcc (which, in all fairness, is many years older) will >occasionally produce code as shown below, even with the optmizer >turned on ...: > > cvtbl -4(fp),r0 > movl r0,r0 # Could be optimized to "nop" :-> > ret Actually, pcc is smart enough not to move a register to itself, at least if you are careful in how you write the machine-dependent code generator. It does often write temporaries unnecessarily, e.g., f(p) char *p; { return (g() ? h() + i() + j() : *p); } which generates calls $0,_g tstl r0 # g()? jeql L99999 calls $0,_i # i() movl r0,-4(fp) calls $0,_j # j() movl r0,-8(fp) calls $0,_h # h() addl2 -4(fp),r0 # +i addl2 -8(fp),r0 # +j jbr L99998 # merge ?: L99999: cvtbl *4(ap),r0 # *p L99998: movl r0,-12(fp) # was hard; store in temp movl -12(fp),r0 # return result ret The 4.3BSD /lib/c2 is able to remove the second movl: L99998: movl r0,-12(fp) ret but the first, while unnecessary, is retained, even though the `hard expression' (needed too many registers, since function calls clobber all the temporary registers) that is being computed by ?: is computed into the return register (via MUSTDO). We could probably fix this by checking, in store() or in its callers, to see whether the expression being stored is a ?:, and if so, whether we only need the result for a return statement.... -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris