home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / inline / part01 next >
Encoding:
Internet Message Format  |  1987-09-14  |  26.3 KB

  1. Subject:  v11i039:  Inline code expander for C, Part01/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: omepd!mcg@uunet.UU.NET
  7. Posting-number: Volume 11, Issue 39
  8. Archive-name: inline/Part01
  9.  
  10. [  Please note The copyright restrictions; if you have problems with them,
  11.    calm reasoned e-mail to Mr. McGeady will probably be most effective.
  12.    Don't send ME mail, as I don't care enough.  --r$  ]
  13.  
  14. I have a submission for comp.sources.unix, my inline code substituter,
  15. 'inline'.  It has been in beta-test for over a month now, and I believe
  16. that it is stable enough to be released.  The next four messages will
  17. contain the four shar files with the source, documentation, test files,
  18. and design notes.
  19.  
  20. A word about the copyright.  I have chosen to copyright the source to
  21. the program, but place the binaries in the public domain.  This is
  22. predominantly to retain control over modifications to the source and
  23. over what people might do with it.  The copyright notice file COPYRIGHT
  24. contains explicit permission for distribution over comp.sources, and
  25. via the archive server, but disallows other distribution.  If there is
  26. a problem with this, please let me know.
  27.  
  28. Thank you for your help.
  29.  
  30. S. McGeady
  31. tektronix!ogcvax!omepd!mcg
  32. intelca!mipos3!omepd!mcg
  33. (503) 696-4393
  34.  
  35. # This is a shell archive.  Remove anything before this line
  36. # then unpack it by saving it in a file and typing "sh file"
  37. # (Files unpacked will be owned by you and have original permissions).
  38. # This archive contains the following files:
  39. #    ./NOTES
  40. #    ./COPYRIGHT
  41. #
  42. if `test ! -s ./NOTES`
  43. then
  44. echo "writing ./NOTES"
  45. sed 's/^X//' > ./NOTES << '\Rogue\Monster\'
  46. X
  47. X
  48. X'Inline' Implementation Notes    -   Mon Apr 27 14:28:43 PDT 1987
  49. X                -   Sat May  9 20:53:04 PDT 1987
  50. X
  51. X(c) Copyright, 1986, 1987, S. McGeady - all rights reserved.
  52. X
  53. X
  54. XGeneral Comments:
  55. X
  56. XThis program was written as part of a challenge.  When discussing the
  57. Ximplementation of an inline substituter with a colleague (Jim Valerio), he
  58. Xsuggested that the best way to do this was by parsing the entire program and
  59. Xrewriting expressions, whereas I felt that it could be done entirely on a
  60. Xlexical level.  I didn't want to go to the trouble of parsing, keeping an
  61. Xentire symbol table, etc.  He felt that one didn't have enough information
  62. Xat the lexical level to do the job.  While I suppose I have proved my point,
  63. XI think that Jim also proved his.  This program consists of over 4000 lines
  64. Xof totally twisted code, and most of the complication herein involves working
  65. Xaround things that wouldn't need to be worked around if I had a parse tree.
  66. XWhile there are areas where I resort to some ad-hoc recursive-descent parsing,
  67. Xfor the most part the problems are solved with goofy lexical heuristics.  I
  68. Xhave pumped a lot of code through this program, and that leaves me to believe
  69. Xit is mostly correct, but I would have felt better if I had a formal grammar.
  70. X
  71. XSome of the biggest problems that I ran into are things I didn't think about
  72. Xoriginally, such as confusing user-defined types (typedefs) and structure tags
  73. Xwith identifiers, problems related to identifier hiding between scopes, and
  74. Xthe parsing and regurgitating of function pointer declarations.
  75. X
  76. XUntil recently, this program didn't support the biggest area where inline
  77. Xfunctions are needed - in the control parts of for() and while() loops,
  78. Xi.e. the places where you need an expression, rather than an embedded
  79. Xlocal-scope block.  I long thought that this problem couldn't be solved
  80. Xwithout a parse tree, but it turns out that the heuristics to expressionize
  81. Xa routine are fairly simple (at least in comparison to the rest of this
  82. Xprogram) - about 300 lines of code.  It is amusing to note that the
  83. Xprevious version of these notes contained the statement, referring to this
  84. Xmodule (rewrite.c) "I have come up with some heuristics for this, but they
  85. Xare too grotesque for even me to put in at this point."  They really
  86. Xaren't that bad.
  87. X
  88. XIn my defense, I did finish this program (insofar as this is finished), and
  89. XJim never finished his.  On the whole, this does a more complete and correct
  90. Xjob than the inliner in the release of C++ that I have seen (an early one),
  91. Xwhich won't handle inlines with loops in them, and which screws up inlines
  92. Xwith multiple returns.
  93. X
  94. XSomeday I may rewrite this to contain a full C parser, but not today.
  95. X
  96. XWhat to expect from this in terms of performance improvement in real code?
  97. XWell, the operative phrase is "your mileage may vary".  I took the
  98. Xwidely-distributed "compress" program, which is a prime candidate for this
  99. Xbecause the input and output routines are called once per character, and
  100. Xare only called once.  For very large files, "compress" was improved by
  101. X10% by making the output routine an inline.  I suspect a more typical
  102. Xexample is 2-5%.  Inlining does *not* generally buy you big increases in
  103. Xperformance, and it is generally *not* going to get you anything in
  104. Xcarefully-crafted C code.  It's major utility is to provide a new feature
  105. Xin C - macros that are not sensitive to side-effects in their arguments,
  106. Xand which can be more complex than cpp macros typically can be.  Perhaps
  107. Xthis will be considered the "prior art" needed for inline's inclusion in
  108. XC next time around.
  109. X
  110. XS. McGeady
  111. X
  112. Xp.s. What follows is a random set of notes on the implementation.  They
  113. X    are mostly notes to myself, but they may be of interest to any
  114. X    masochists out there who might want to work on this.  Warning -
  115. X    they may be out of date - when in doubt, believe the notes in
  116. X    the code, and the code itself.
  117. X    
  118. X-----------------
  119. X
  120. XModules:
  121. X    inline.h    - basic data structure declarations, forward decls
  122. X    tokens.h    - symbolic names for C tokens
  123. X    inline.c    - mainline program, command-line parsing, main loop
  124. X    declare.c    - routines to declare an inline function when one
  125. X              is discovered
  126. X    expand.c    - routines to detect and expand an inline
  127. X    rewrite.c    - rewriting rules for expressionizing
  128. X    utils.c        - a set of utility routines
  129. X    yylex.c        - the lexical analyzer
  130. X    mem.c        - a general-purpose memory allocator, useful
  131. X              for large numbers of small allocations
  132. X    tokens.c    - the string table for the tokens
  133. X
  134. X    scan.l        - no longer part of the program, the original lex-based
  135. X              lexical analyzer
  136. X
  137. X---
  138. X
  139. X    test.c        - not part of the program, a validation file for inline
  140. X
  141. X----------------
  142. X
  143. XOverall Strategy:
  144. X
  145. X
  146. XThe general technique is to take a declaration like:
  147. X
  148. X    inline int foo(a,b) {
  149. X        int c;
  150. X
  151. X        return(c = a+b);
  152. X    }
  153. X
  154. Xand a call to it like:
  155. X
  156. X    boff = foo(x+y,400);
  157. X
  158. X
  159. Xand turn it into a local block like:
  160. X
  161. X    {
  162. X        int __foo_a; int __foo_b;
  163. X        int __foo_retval;
  164. X        __foo_a = (x+y);
  165. X        __foo_b = (400);
  166. X        {
  167. X            int c;
  168. X            __foo_retval = c = __foo_a + __foo_b;
  169. X            goto __foo_end;
  170. X        }
  171. X    __foo_end:
  172. X        boff = __foo_retval;
  173. X    }
  174. X
  175. XAdditionally, we turn it into an expression like:
  176. X
  177. X    (retval = c = a+b),retval
  178. X
  179. XIn case it is used in one of these sorts of contexts:
  180. X
  181. X    while(foo(1,2)) { ... }
  182. X    for ( ; x < foo(2,3); ..) { ... }
  183. X
  184. XWe also try to do some optimization on the actual parameters themselves,
  185. Xonly assigning them to block-locals (e.g. __foo_a) when they are either
  186. Xassigned to inside the inline or when they have side-effects (e.g. foo(x++,y)),
  187. Xso that the actual expansion above looks more like:
  188. X
  189. X    {
  190. X        int __foo_a; int __foo_b;
  191. X        int __foo_retval;
  192. X        {
  193. X            int c;
  194. X            __foo_retval = c = (x+y) + (400);
  195. X            goto __foo_end;
  196. X        }
  197. X    __foo_end:
  198. X        boff = __foo_retval;
  199. X    }
  200. X
  201. X
  202. XThere are a myriad of other little issues, including renaming variables
  203. Xso as not to conflict with those in enclosing scopes, etc.  To avoid any
  204. Xnaming conflicts, the following variable renaming is done:
  205. X
  206. X    1) if a procedure calls an inline, all of it's local variables
  207. X       are changed to '_auto_var'  (where 'var' is the original variable
  208. X       name).  this prevents collision of external references from inlines
  209. X       that have been expanded with local variables of the same name
  210. X       in the calling routine;
  211. X
  212. X    2) formal parameter names in inlines are changed to avoid
  213. X       conflicts during initialization.  they are changed to
  214. X       __foo_formal (where 'foo' is the inline function name and 'formal'
  215. X       is the formal name;
  216. X
  217. X    3) variables in locally-scoped block within inlines are renamed
  218. X       to '_loc_var_lev' (where 'var' is the variable name and 'lev'
  219. X       is a digit indicating the scoping level), so that when the
  220. X       statement is expressionized and all of the initializations are
  221. X       moved to the same level, the local variables remain unique;
  222. X
  223. X----------------
  224. X
  225. XDetailed Design:
  226. X
  227. X
  228. XThe input program is tokenized by the routine gettok() (called from doproc(),
  229. Xseel below), which in turn calls yylex() (yylex was originally the lex program
  230. Xembodied in "scan.l", but has been replaced by a customized version which is
  231. Xabout 20% faster).  The tokenizer preserves whitespace, comment, and CPP-line
  232. Xtokens so the program can be recreated in its original form.  The lexer is
  233. Xentirely contained in yylex.c, and is completely straightforward.  Tokens
  234. Xare represented in data structures of type 'struct token'.  This structure
  235. Xcontains a bunch of information - see inline.h.
  236. X
  237. XThe mainline calls doproc(), the generic main loop.  It gathers up
  238. X"procedures", which are defined as a string of text following a semicolon or
  239. Xright brace at brace depth 0 and continuing to a right brace at brace depth 0.
  240. XThe program gathers up typedefs from this, so it knows the difference between
  241. Xuser-defined types and regular identifiers.  This procedure calls the
  242. Xprocedures dolocals(), doargs(), addlocal, islocal(), and clearscope() to
  243. Xhandle the renaming of local identifiers, so they don't clash with those found
  244. Xin wider scopes (if you can't imagine the problem, don't worry about it).  The
  245. Xroutines pushscope() and popscope() handle typedefs in inner scopes.
  246. X
  247. XDoproc() builds a list of tokens (based around the 'toklist' structure) and,
  248. Xwhen it sees a right brace (signifying the end of a function), calls
  249. X'isdecl()' [declare.c] to see if it is an inline declaration.  If it is,
  250. X'dodecl()' [declare.c] is called to process the inline declaration, otherwise
  251. Xwe call 'doinline()' [expand.c] to detect any usages of inline functions
  252. Xin the routine and expand them, if possible.  Following expansion (or lack
  253. Xthereof) we return to the mainline, where the procedure is dumped out, and
  254. Xaround we go again.  A flag is carried around to prevent local variable
  255. Xrenaming in the case that a procedure contains no inlines - this allows
  256. Xinline to make no changes to programs that do not use inlines.
  257. X
  258. XDodecl(), in declare.c is the main entrypoint for the declaration of inline
  259. Xfunctions.  The module declare contains these entrypoints:
  260. X
  261. X    dodecl()    - overall inline declaration handling
  262. X    doident()    - handle identifiers inside inlines
  263. X    doreturn()    - handle the return stmt in an inline
  264. X    doretlab()    - put the label that a return goes to after an inline
  265. X    putdecl()    - issue a "forward declaration" line
  266. X    isassigned()    - return true if a variable occurs as an lvalue
  267. X    doformals()    - rewrite the declarations part of an inline for use
  268. X              as an expansion
  269. X    isformal()    - return true if the identifier is in the formal
  270. X              parameter list of this node
  271. X    isdecl()    - return true if this token stream is an inline def
  272. X    dotypedef()    - handle typedef's, as noted above
  273. X
  274. XDodecl() gathers an inline declaration, breaking it into and/or creating the
  275. Xfollowing pieces, which are parts of the overall inline data structure,
  276. X'struct inline_node':
  277. X
  278. X    SDECL    - the declaration part itself, from the 'inline' keyword
  279. X          to the opening parenthesis of the formal list
  280. X
  281. X    SFORMAL    - the formal parameters of the inline, from the opening
  282. X          paren to the closing paren
  283. X
  284. X    SOPARAMDECL - any tokens between the closing paren of the formal
  285. X          list and the opening brace of the function (only present
  286. X          in pre-ANSI X3J11 declarations)
  287. X
  288. X    SBODY    - the body of the inline, from the opening brace to the
  289. X          closing brace
  290. X
  291. X    SEXPRDECL - declarations for the expression form of the inline
  292. X
  293. X    SEXPRBODY - the body of the expression form of the inline
  294. X
  295. X
  296. Xfor example, for a pre-ANSI X3J11 declaration:
  297. X
  298. X
  299. X    SDECL        inline struct foo *bar
  300. X    SFORMAL         (a,b,c)
  301. X    SOPARAMDECL     int a,b,c;
  302. X    SBODY        { return(a+b+c); }
  303. X
  304. Xfor a X3J11 declaration:
  305. X
  306. X    SDECL        inline struct foo *bar
  307. X    SFORMAL         (int a, int b, int c)
  308. X    SBODY        { return(a+b+c); }
  309. X
  310. X
  311. XAs dodecl() is breaking up the program, once it gets to the BODY part, it
  312. Xcalls doformals(), which parses the SFORMAL and (potentially) the SOPARAMDECL
  313. Xparts into another stream of tokens (SDECLBODY) which represents the
  314. Xdeclarations for block-local variables to be placed at the beginning of
  315. Xthe expansion block.  Its action (both in an idealized sense and its
  316. Xactual implementation) is explained in detail in a comment about the routine.
  317. X
  318. XThe dodecl() iterates through the body of the inline, calling doident()
  319. Xeverytime it finds an identifier.  If the identifier is a formal parameter,
  320. Xit is replaced by a placeholder which is expanded at inline expansion time
  321. Xinto a new identifier of the form: "foo_id_0" where "foo" is the inline
  322. Xname, "id" is the original identifier, and "0" is a sequence number (to
  323. Xhandle recursive expansions).
  324. X
  325. XDodecl() also detects and handles the "return" statement (by calling
  326. Xdoreturn() and doretlab()), changing returns into an assignment to a
  327. Xspecially-constructed return value holder and a goto.
  328. X
  329. XFinally, before returning, dodecl() calls rewrite() to attempt to
  330. Xrewrite the inline function as an expression.  If rewrite() succeeds, then
  331. Xthat success is so marked in a flag in the node structure, otherwise
  332. Xdodecl() frees the memory used in the abortive attempt. (Rewrite is further
  333. Xdiscussed below).
  334. X
  335. XDoinline(), in expand.c, is the main entrypoint for the expansion process.
  336. XIt marches through a token list looking for identifiers which correspond
  337. Xto the identifiers seen so far declared as inline, and which occur in a
  338. Xcontext that appears to be a procedure call (this latter test handles the
  339. Xcase of a local-scope id hiding a globally-scoped function id).
  340. X
  341. Xexpand.c has the following entrypoints:
  342. X
  343. X
  344. X    doinline()    - overall expansion handler
  345. X    dostmt()    - find end of statment
  346. X    doexpr()    - find end of expression (used by dostmt())
  347. X    doexpand()    - perform expansion of node
  348. X    doactuals()    - gather actuals from calling statement
  349. X    mkenode()    - make an "expansion node"
  350. X    sideeffect()    - return true if the expression has a side-effect
  351. X
  352. X
  353. XWhen doinline() finds a candidate for expansion, it checks to see if it
  354. Xoccurs in a non-expandable context, such as in a control statement or
  355. Xin an initialization.  Assuming it is expandable, it first gathers the
  356. Xtokens representing the actual arguments to the inline by calling
  357. Xdoactuals(), then it locates the end of the statement (with dostmt()),
  358. Xand then expands the inline body around the statment (with doexpand()).
  359. XDoinline() carefully keeps track of up to three points in the token stream:
  360. Xthe "beginning" of the current statement (defined as the token after the
  361. Xpreceeding semicolon, label, or left or right brace), "here", the current
  362. Xtoken (only needed when an expansion is found), and the "end" of the current
  363. Xstatement, which is either a semicolon, or a closing brace, depending on
  364. Xwhether the statement opened with a brace or not.  These are passed to
  365. Xdoexpand().
  366. X
  367. Xdoactuals() is straightforward, gathering tokens until it sees commas.
  368. XIt fills part of the "expansion node" structure which holds all the
  369. Xdata for the current expansion.
  370. X
  371. Xdoexpand() is the tricky part, and though its main job is to simply expand
  372. Xthe stored inline node at the current place, it actually also does some
  373. Xrewriting of the expansion code, including rewriting the declaration of
  374. Xthe return value holder, inserting initializations of local formal parameter
  375. Xholders to the actuals (if they are needed - it tries to optimize these
  376. Xaway in the absence of use as lvalues or when actuals have side-effects),
  377. Xand filling in the names of formal parameter holder id's with specially-
  378. Xconstructed names.  That part beginning with the inline identifier and
  379. Xextending through the tokens that are part of the call itself (i.e. up to a
  380. Xright paren at the same level as the inline function identifier) are replaced
  381. Xwith the return value holder, which has been previously set.  If the expansion
  382. Xis in a place where expansion of this sort is not possible, then the
  383. Xinline's expressionized form is inserted at this point, if one is available.
  384. X
  385. XDoexpand() also keeps track of situations where it can't expand inlines.
  386. XIt maintains a count of these cases, and the mainline, at the end of the
  387. Xprogram, emits the bodies of those inlines which had calls which could
  388. Xnot be expanded, so that the references are satisfied.
  389. X
  390. X-----------------
  391. X
  392. Xutility routines in utils.c:
  393. X
  394. Xskipws(t)        - skip whitespace tokens,
  395. X              return pointer to next non-ws token
  396. X
  397. Xaddtok(list,tok)    - add a token to a toklist struct
  398. X
  399. Xinstok(tok,ntok)    - insert a token list after the named token
  400. X
  401. Xnewtok(mem,val,id)    - create a partially filled-on token struct
  402. X
  403. Xduptok(mem,tok)        - copy a token (creating a new one)
  404. X
  405. Xcpytoklist(mem,olist,ilist)    - copy a token list (creating a new one)
  406. X
  407. Xmkstr(mem,va_alist)    - concatenate a list of strings into a single string
  408. X
  409. Xerror(line,fmt,args)    - print an error message
  410. X
  411. Xwarn(line,fmt,args)    - print a warning message
  412. X
  413. Xitoa(n)            - very simple itoa for variable sequence numbers
  414. X
  415. Xmknode(mem)        - allocate a "node" structure (inline node)
  416. X
  417. Xprtoklist(tl,s)        - print a token list on FILE s
  418. X
  419. Xprtok(tok,s)        - print an individual token
  420. X
  421. Xdebugnode(node)        - print some debugging info about an inline node
  422. X
  423. Xistype(tok)        - return true if 'tok' is a type specifier
  424. X
  425. Xisstoreclass(tok)    - return true if 'tok' is a storage class
  426. X
  427. Xiscontrol(tok)        - return true if 'tok' is a control keyword
  428. X
  429. Xiscall(tok)        - return true if token list looks like a function call
  430. X
  431. X-----------------
  432. X
  433. Xmem.c:
  434. X
  435. Xmem.c implements a general-purpose memory allocator tuned for allocating
  436. Xa large number of small amounts of memory, groups of which will be freed
  437. Xall at once.  The primary entrypoints are:
  438. X
  439. X    openpool()
  440. X    closepool()
  441. X    getmem()
  442. X
  443. Xopenpool() creates a pool from which memory is allocated by subsequent
  444. Xgetmem() calls.  openpool() returns an integer handle for the memory pool,
  445. Xwhich is then passed to getmem(), so multiple pools can be open at the
  446. Xsame time.  Variables holding this handle are uniformly called 'mem'
  447. Xin inline.  closepool() frees all the pieces allocated in a poll, making
  448. Xthem available to further getmem() allocations for other pools.
  449. X
  450. XThe prime advantage of this over the alternative of replacing getmem()
  451. Xwith malloc() is that the average allocation requested in this program is
  452. Xonly 20 bytes long, and the overhead of a malloc() block is close to
  453. Xor greater than this.
  454. X
  455. XUnfortunately, getmem() is still the main time-user in the program.
  456. XIt could be speeded up a little by removing the statistics-gathering
  457. Xcode.
  458. X
  459. X------------------
  460. X
  461. X
  462. X
  463. X------------------------------------------------------------------------
  464. XRandom Implementation Notes:
  465. X------------------------------------------------------------------------
  466. X
  467. Xhard cases:
  468. X
  469. X    inline foo() {}
  470. X
  471. X    m() {
  472. X        switch(foo()) {
  473. X            ...
  474. X        }
  475. X    }
  476. X
  477. Xbecomes:
  478. X        {
  479. X        int retval;
  480. X            {
  481. X            /* expansion */
  482. X            }
  483. X        switch(retval) {
  484. X            ...
  485. X        }
  486. X        }
  487. X
  488. X(note - need to match entire switch as the statement)
  489. X
  490. X---------------------------
  491. X
  492. Xm() {
  493. X    if (foo()) {
  494. X    } else { }
  495. X
  496. X    if (foo()) stmt;
  497. X    else stmt;
  498. X}
  499. X
  500. X---------------------------
  501. Xm() {
  502. X    a = foo() + foo();
  503. X
  504. X    a = foo(foo(1));
  505. X
  506. Xfirst becomes:
  507. X
  508. X    {
  509. X    int retval1; int retval2;
  510. X    int params;
  511. X
  512. X        params = actuals;    
  513. X        { expansion }
  514. X        params = actuals;    
  515. X        { expansion }
  516. X
  517. X    a = retval1 + retval2;
  518. X    }
  519. X
  520. Xsecond becomes:
  521. X
  522. X    {
  523. X    int retval;
  524. X    int params1;
  525. X        {
  526. X        int retval;
  527. X        int params2;
  528. X            params2 = actuals;
  529. X            { expansion }
  530. X        
  531. X        params1 = retval;
  532. X        }
  533. X        { expansion }
  534. X    a = retval;
  535. X    }
  536. X
  537. XThis is handled in the following way: the expression is scanned token by
  538. Xtoken from left to right.  When the first inline is called, it is
  539. Xexpanded in the normal way, and the remaining tokens on the line are copied
  540. Xwithout change (including the tokens representing the subsequent inline
  541. Xcall).  HOWEVER, following this expansion, the token pointer is reset to
  542. Xthe beginning of the expression, and it is *rescanned* for additional
  543. Xexpansions.  This handles the following:
  544. X
  545. X    1) expansions of inline calls within other inlines' definitions
  546. X    2) expansions of inlines as arguments to inline calls
  547. X    3) multiple inline calls in the same expression
  548. X
  549. XNote that there is a possibility for recursive inline expansion - this
  550. Xis not detected, e.g.:
  551. X
  552. Xinline foo() { bar(); }
  553. Xinline bar() { foo(); }
  554. Xm() { foo(); }
  555. X
  556. Xwill cause inline to core-dump (probably after consuming all available
  557. Xmemory).
  558. X
  559. X---------------------------
  560. XCan't expand these:
  561. X
  562. Xm() {
  563. X    register int i = foo();
  564. X    int b;
  565. X
  566. X    ...
  567. X}
  568. Xm() {
  569. X    while(foo()) {} /* can't do this */
  570. X
  571. X    do {
  572. X        ...
  573. X    } while(foo());    /* can't do this */
  574. X
  575. X    for ( x; foo(); x ) { ... }
  576. X
  577. X    for ( x; x; foo()) { ... }
  578. X
  579. X    /* should be able to do this, but can't now */
  580. X    for (i = foo(); x ; x ) { ... }
  581. X
  582. X[Actually, we can expand all but the first case now, with the advent of
  583. Xexpressionizing.]
  584. X
  585. X-------------------------
  586. X
  587. Xuseful but difficult optimizations:
  588. X
  589. X    in expansion:
  590. X
  591. X        { ...
  592. X        {
  593. X            ...
  594. X            goto _foo_end;
  595. X        }
  596. X        _foo_end:
  597. X        }
  598. X
  599. X    should remove the final goto
  600. X
  601. X    but, last statement might be:
  602. X
  603. X        while(...) return;    /* bogus but legal */
  604. X
  605. X    (note that if(...) return --> if (...) ; is ok)
  606. X
  607. X[this is still not fixed.  hard to know a good heuristic.]
  608. X
  609. X-------------------------
  610. X
  611. X    in a call with constant arguments, if arguments are used
  612. X    only as rvalues, the insert actuals in place of param holders:
  613. X
  614. X    foo(1,2);
  615. X
  616. X        instead of
  617. X            {
  618. X            param1 = 1; param2 = 2;
  619. X                {
  620. X                    x = param1;
  621. X                    y = param2;
  622. X                    ...
  623. X                }
  624. X            }
  625. X
  626. X        should do:
  627. X            {
  628. X            {
  629. X                x = 1;
  630. X                y = 2;
  631. X            }
  632. X            }
  633. X
  634. X        except for:
  635. X
  636. X            inline foo(x,y) {
  637. X                x = y;    /* for whatever reasons */
  638. X            }
  639. X    
  640. X    note that inserting symbolic actuals has exactly the same problem,
  641. X    with the additional problem of name collision
  642. X
  643. X    we can do this optimization IFF we know that the parameters of the
  644. X    inline function are never used as lvalues.
  645. X
  646. X    heuristic for l-value-ness: doesn't appear in stmt on left side
  647. X    of '=' type operators, never has ++ or -- applied to it.  others?
  648. X-------------------------
  649. X
  650. X    filling in return value is simpler, but not trivial:
  651. X
  652. X        x = foo();
  653. X
  654. X    should have 'x' inserted as the return value variable, except if:
  655. X
  656. X        1) there is a name conflict;
  657. X        2) the lvalue 'x' has a side-effect (e.g. *p++)
  658. X
  659. X    the latter can be easily handled
  660. X
  661. X-------------------------
  662. X
  663. X[note: this section is handled by expressionizing, rather than the way
  664. Xhypothesized.]
  665. X
  666. X    note that we can't expand:
  667. X
  668. X        if (a && foo(1,2)) {
  669. X            ...
  670. X        }
  671. X
  672. X    in the obvious way because of side-effect problems (foo has side
  673. X    effects).
  674. X
  675. X    could do (but don't currently):
  676. X
  677. X        if (a) {
  678. X            <expansion of foo(1,2)>
  679. X            if (retval) {
  680. X                ... <body of if>
  681. X            }
  682. X        }
  683. X
  684. X    also
  685. X        if (a || foo(1,2)) {
  686. X            ...
  687. X        }
  688. X
  689. X    becomes:
  690. X        if (a) goto body;
  691. X        <expansion of foo(1,2)>
  692. X        if (retval) {
  693. X        body:
  694. X            ... <body of if()>
  695. X        }
  696. X
  697. X    need to apply this recursively, need to take care with parens,e.g.:
  698. X
  699. X    if ((a && foo(1,2)) || (b && bar(1,2)) {
  700. X        ...
  701. X    }
  702. X
  703. X    if ((a)) {
  704. X        <expansion of foo(1,2)>
  705. X        if (retval || (b && bar(1,2)) {
  706. X            ...
  707. X        }
  708. X    }
  709. X
  710. X    then
  711. X
  712. X    if ((a)) {
  713. X        <expansion of foo(1,2)>
  714. X        if (retval) goto body;
  715. X        if (b && bar(1,2)) {
  716. X        body:
  717. X            ...
  718. X        }
  719. X    }
  720. X
  721. X    then
  722. X
  723. X    if ((a)) {
  724. X        <expansion of foo(1,2)>
  725. X        if (retval_foo) goto body;
  726. X        if (b) {
  727. X            <expansion of bar(1,2)>
  728. X            if (retval_bar) {
  729. X             body:
  730. X                ...
  731. X            }
  732. X        }
  733. X    }
  734. X
  735. X-----------------------
  736. X
  737. Xpossible heuristic for expression-izing series of statements:
  738. X
  739. X    stmt1;
  740. X    if (cond) {
  741. X        stmt2;
  742. X        stmt3;
  743. X    } else {
  744. X        stmt4;
  745. X        stmt5;
  746. X    }
  747. X    return(expr);
  748. X
  749. X    becomes:
  750. X
  751. X    stmt1,
  752. X    ( (cond) ? (stmt2,stmt3) : (stmt4,stmt5) ),
  753. X    expr
  754. X
  755. Xwhat about multiple returns?
  756. X
  757. X    if (cond) {
  758. X        stmt1;
  759. X        return(expr1);
  760. X    } else {
  761. X        if (cond2) {
  762. X            stmt2;
  763. X            return(expr2);
  764. X        }
  765. X    }
  766. X    return(expr3);
  767. X
  768. X(Note that C++ release 1.0 does this wrong)
  769. X
  770. X
  771. Xreplace "return(expr)" with "retval = expr" in all cases, but
  772. Xdrop goto's, and add evaluation of retval as last expression, i.e:
  773. X
  774. X    ((cond) ?
  775. X        (stmt1, retval = expr1)
  776. X    : (
  777. X        (cond2) ?
  778. X            (stmt2, retval = expr2)
  779. X        :
  780. X            0
  781. X    )), retval
  782. X
  783. X--------------------------------------------------------
  784. X
  785. Xweird problems in C (scope rules):
  786. X
  787. Xwhat does this mean?:
  788. X
  789. X    int var;
  790. X
  791. X    func(var)
  792. X    char *var;
  793. X    {
  794. X        struct { char x; } var;
  795. X
  796. X        { int var; var = 1; }
  797. X    }
  798. X
  799. Xthis compiles under PCC, but C++ gives an error on the redeclaration of
  800. Xthe formal parameter 'var'.
  801. X
  802. X[We punt.]
  803. X
  804. X--------------------------------------------------------
  805. \Rogue\Monster\
  806. else
  807.   echo "will not over write ./NOTES"
  808. fi
  809. chmod 444 ./NOTES
  810. if [ `wc -c ./NOTES | awk '{printf $1}'` -ne 22776 ]
  811. then
  812. echo `wc -c ./NOTES | awk '{print "Got " $1 ", Expected " 22776}'`
  813. fi
  814. if `test ! -s ./COPYRIGHT`
  815. then
  816. echo "writing ./COPYRIGHT"
  817. sed 's/^X//' > ./COPYRIGHT << '\Rogue\Monster\'
  818. X
  819. XThe source code to this program ('inline') is copyrighted, and all rights
  820. Xare reserved by the author.  The copyrighted files include the C source files
  821. Xand header files (all these files have copyright notices on them).
  822. XRedistribution of this source code requires explicit permission from the
  823. Xauthor.  The author explicit grants permission to the comp.sources
  824. Xmoderators to redistribute the source code to end-users.  Other persons
  825. Xwishing to redistribute this code must have permission from the author. (*)
  826. X
  827. XPermission is hereby granted to distribute the binary object code for this
  828. Xprogram without explicit permission from the author, so long as such
  829. Xdistribution is not for profit.
  830. X
  831. XThe Manual page for this program is hereby placed in the public domain.
  832. X
  833. X4/30/87
  834. X
  835. XSteven McGeady
  836. X3714 SE 26th Ave.
  837. XPortland, OR 97202
  838. X(503) 235-2462
  839. X(503) 696-4393
  840. Xtektronix!ogcvax!omepd!mcg
  841. Xintelca!omepd!mcg
  842. X
  843. X(*) I am taking the position that the posting of "diffs", including
  844. Xreasonable context diffs, is "fair use", and is permitted (or at least
  845. XI won't complain about it).  However, I would prefer if all modifications
  846. Xwere sent to me first.
  847. X
  848. X
  849. \Rogue\Monster\
  850. else
  851.   echo "will not over write ./COPYRIGHT"
  852. fi
  853. chmod 444 ./COPYRIGHT
  854. if [ `wc -c ./COPYRIGHT | awk '{printf $1}'` -ne 1134 ]
  855. then
  856. echo `wc -c ./COPYRIGHT | awk '{print "Got " $1 ", Expected " 1134}'`
  857. fi
  858.