At 0:08 Uhr -0400 10.10.2006, Bradley Lucier wrote:
Perhaps one can use a similar strategy for inlining equal?
I'm sometimes defining functions like |equal?| or |force| myself in some module (or more precisely: in some compilation block (I'm almost always using the block compilation declaration)), which is kind like inlining -- the compiler may actually inline it in some cases; but at least it's cheaper to call when inside the same block than across block/module/sharedobject (not sure which word I should choose to name it accurately) boundaries.
I'm wondering: in which step of the compilation phase are inlinings of the kind that you are suggesting done? Is it in the code generation step? So will it inline the code *always*, even multiple times in the same compilation block, and not be subject to the inlining-limit declaration? If so, wouldn't it be better to change that to actually create a function, but in the same block, and let the function inliner decide how to handle that? In my measurements, a real function call in the same block is only about 30-40 cycles or so, whereas a function call across block boundaries is about 200 cycles (or was it 240?). Probably for something like |equal?| it's good enough to reduce the overhead from ~200 cycles down to 30-40. This should help reduce the code bloat.
Handling "optional inlining" is something I plan to do in chjmodule (I'm continuing to work on it currently), so that one can export functions from some module A as "inlinable", which means that they will be copied verbatim (but within the original namespace, by putting a ##namespace declaration around/into it) into caller modules, so e.g. module B importing module A will contain such a copy in it's toplevel. That doesn't necessarily mean that it is being inlined into every call site inside B: it's open to the normal Gambit inliner. At the very least the costs drop from ~200 to 30-40 cycles.
Using such module techniques, instead of hard coding functions like |equal?| into Gambit, they could be defined in a standard module like "R5RS" with an inlinable export flag and be imported from there.
(BTW one could also split |equal?| like that:
(define (equal? a b) (or (eq? a b) (real-equal? a b))) (define (real-equal? a b) ..recursive definition))
and so make it possible that the first part, which doesn't generate much code bloat, can be inlined whereas the rest still isn't.
Christian.