Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-crg!nike!sri-spam!parcvax!hplabs!tektronix!uw-beaver!uw-june!entropy!dataio!bright From: bright@dataio.UUCP (Walter Bright) Newsgroups: net.lang.c Subject: Re: Orphaned Response Message-ID: <1074@dataio.UUCP> Date: Fri, 22-Aug-86 12:31:39 EDT Article-I.D.: dataio.1074 Posted: Fri Aug 22 12:31:39 1986 Date-Received: Sun, 24-Aug-86 20:50:22 EDT References: <273@watmath.UUCP> <86900019@haddock> Reply-To: bright@dataio.UUCP (Walter Bright Organization: Data I/O Corp., Redmond WA Lines: 47 In article <86900019@haddock> karl@haddock writes: >ccvaxa!aglew (Andy Glew) writes: >>[haddock!karl (Karl Heuer) writes:] >>>I was trying to declare "typedef void dead;" so that I could distinguish >>>between functions that return nothing (void perror(char *), setbuf(FILE *, >>>char *), nullf(void)) from those that don't return (dead exit(int), >>>abort(void), longjmp(jmp_buf, int)). >> >>Good point, though - an optimizing compiler could take advantage of >>knowledge that a function doesn't return to do better register allocation, >>etc. > > The only >reasons for not adding [dead functions], as far as I can see, are as follows: > >[2] It won't be usable much. This is a valid point. There were a *lot* of >nonvalued int functions before void was invented; there are only a handful of >standard functions that are dead-ends. Functions that never return are used a LOT in code that is loaded with self-debugging assertion macros: #define assert(e) ((e) || printmsgandexit("e",__LINE__,__FILE__)) >As for optimization, the calling >function can take advantage of the knowledge by omitting extra branches (e.g. >in "if (err) exit(1); else ...") or returns ("exit(0)" at the bottom of >main()). This improves the space (but not time) efficiency, but not by much. > >I presume your comment about register allocation referred to the dead-end >itself, in that the caller's registers need not be saved. I don't think you >can assume this: the function "dead f() { for (;;) pause(); }" could be >interrupted by a signal, whose handler could longjmp() to f's caller, whose >registers must be recoverable. For similar reasons, it probably isn't okay >to optimize the function call into a jump, unless you're careful with the >stack. A good optimizer can make some important optimizations if it knows that a function will never return: 1) Register contents destroyed by the function call do not affect the caller. This has important ramifications when doing register allocation by coloring. 2) Functions are presumed to modify all globals and all indirect references. Thus, if the function does not return, the optimizer can find more common subexpressions, copy propagations, etc.