Using my asm-generator with Exypery.

sig siguctua at gmail.com
Wed May 9 03:02:53 UTC 2007


On 08/05/07, bryce at kampjes.demon.co.uk <bryce at kampjes.demon.co.uk> wrote:
> sig writes:
>  > Consider following example:
>  >
>  > you write the code:
>  > ------
>  > PrimitiveSmallIntegers>>add: a with: b
>  > | result |
>  >    self pragma: #inline.  "tell the parser to not generate prologue/epilogue"
>  >
>  > " adding pair of smallintegers (assuming a and b is smallintegers!!) "
>  >
>  > ^ ( result := a + b ) ifNotOverflow: [ result - 1 ] else: [ self call:
>  > #coerceToBigIntsAndAdd:with: with: a with: b ]
>  > -------
>  > and then in
>  >
>  > IntermediateGenerator>>generate:add:
>  > ^ self parsedMethod: #add:with:  "return inlined form for adding two operands"
>  >
>  > It provides an easy way for extending Exupery with all basic numerics
>  > functionality (like big integers/floats), without jungles of hardly to
>  > write and hardly to manage mid-level code.
>
> Generating intermediate is not hard, and has good support for unit
> testing.
>
> For use in Exupery primitives must be implemented in the mid level
> code because that exists to allow for easy optimization of waste
> across bytecodes (or primitives).
>
> For instance "a < b ifTrue: [...]"
>
> Will remove the conversion to then from a boolean object for the
> SmallInteger case. Only if a floating point < primitive was inlined
> into medium level intermediate could this optimisation be done.
>
> Which is similar to removing the temporary float created in "1.0 + 2.0
> + 3.0".

Yes, this is what you called high level itermediate, which is then
expanded to low level intermedite by doing optimizations before
entering low-level.
At this low-level point you already working with registers, not
objects, so you can inline asm-code generated by asm-generator.
I think that all IntermediateEmitter>>expanded:.... can be replaced by
inlining asm-methods which will have clean and easy to read syntax.

>
> There are several different kinds of primitive:
> * Small frequently called ones. e.g. #at: and #at:put:
> * Larger important clean primitives (possibly large integer stuff)
> * Larger or infrequent unclean primitives
> * Interfacing to C
> * Performance optimizations.
>
> The small frequently called primitives are compiled into code
> customized for each receiver class. There's only a handful of them
> and most of them are inlined into interpret() in the interpreter.
> interpret () accounts for 70% of the time in the benchmarks I've
> analyzed so performance wise it's the area to focus on.
>
> The larger clean primitives could be quickly implemented by calling
> a C helper function. These could be either compiled as part of
> their methods or inlined.

>
> The larger infrequent unclean primitives are operations that may
> change the active context. Here Exupery would need to save all
> the state back into the context, call the C helper function, then
> load it back and potentially enter a different method. The only
> overhead that can be saved is some of the message sends by using
> PICs.
>
> Interfacing to C could use some support. I haven't looked at it.
>

I am sure, that when you going to C level, you can use asm-generator
instead. For fully equivalent usage potential we need, of course, some
pointers from VM to be able calling another VM functions or access
globals.

> Some of the performance optimizations should be replaced with
> normal Smalltalk as Exupery get's faster. Some should stay as
> tolerable interpreted performance is still nice.
>
>
> To be inlined a primitive must be able to execute in both it's
> senders context (in case it isn't inlined) and in it's senders
> context (in case it is inlined). If you send, or GC from your
> own context you must save the stack pointer and context state
> while if you're in the senders context you mustn't save the
> stack pointer. This is easy to implement using generated code
> but not using a template.
>
i'm not sure what you talking about. A compiled asm primitive acts in
same manner as C function, so when you need to call GC, you call it
without asking anyone.
For inlining a med-code generated by asm-generator you can add a
special MedGC (or whatever) which expands to noop when its inlined and
expands to some calls when its standalone.
For example, parser puts MedScopeArgument at point where your
asm-method accessing the method argument. Then, when you generating
inline code, this med is replaced by supplied register, and for
standalone function, it replaced with instruction(s) which loading
value from stack, or from anywhere you want.
A low level med-code generated by parser is much like a #define macro
in C to me.


More information about the Exupery mailing list