On 08/05/07, [EMAIL PROTECTED] <[EMAIL PROTECTED]> 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.
_______________________________________________
Exupery mailing list
[email protected]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/exupery