Everything is a Register!

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Everything is a Register!

Igor Stasenko
My explo[it]ration of Exupery brings some fruits - an assembler
generator using smalltalk syntax. :)

I don't know how this package might be useful - you decide.
I'm just making it accessible for potential users.

Generator takes a given method source code (not bytecode) and
transforms it to pure asm instructions (with help of Exupery).
The way its done is like what VMMaker does, which also parses a method
and creates it analogue in C.

Take a look at sample asm program:

message3
| a b c |
c := 1.
b := 2.
(b + c) ifLess: [
a := 5.
(b - 1) ifZero: [ a := 10 ]
].
^ a
First thing to remember: everything is a register not an object!
You allowed to assign them, return , make mem/ariphmetic/logical ops.
The control flow selectors is based on processor flags (so using
ifTrue/IfFalse is pointless here and will lead to DNU). All set of
selectors you can find in #AsmSelectors

The example given before produces a following intermediate form:

((block 1
  (mov 1 't2')
  (mov 2 't3')
  (add 't3' 't2')
  (jge block5))
(block 2
  (mov 5 't1')
  (sub 't3' 1)
  (jnz block4))
(block 3
  (mov (mov 10 't1') 't5'))
(block 4
  (mov 't5' 't4'))
(block 5
  (return 't1')))

It then can be processed furter with Exupery with
optimization/registers allocation to get a ready to run assembler
code.

I plan to add support to far calls and inlining (which is easiest part).
The calls (and any special instruction) started from self as receiver.

I plan to add following:

self pragma: #inline
self pragma: #cdecl
self pragma: #apicall

- to indicate which prologue/epilogue generate for function. #inline
can be compiled as standalone function only in case if you do not have
any parameters on it (unary selector).

self call: #selector:with:with with: .. with: .. ...

- this one for local call of a function which must be present in same
class, where parsed method resides. It can be inlined if you put self
pragma: #inline in its source.

self inlinecall: #selector:with:with with: .. with: .. ...

- same as above, but forcing inline.

self callC: #selector:with:with with: .. with: .. ...
self callApi: #selector:with:with with: .. with: .. ...

- this one for external calls using appropriate calling convention far
beyond the squeak :) You must register an Integer address for given
selector in some dictionary of external selectors.

A potential use of this stuff is a callbacks. I'm not decided yet how
to hook it with VM (some advice with Bryce is needed) , but i think
this can be solved in elegant manner.
Also, i have pervasive intentions to allow hot-swapping a core VM
routines, so VM will recompile itself without knowing about it :)

And moreover, in some far future i might want that _full_ C source of
VM will look like following:
int main(...)
{
buf = loadImage();
(void fn*) = buf->entryPoint;

return fn();
}

You can filein an .st file in attached rar. Its not overrides
anything, so if you curious you can file it in without a risk of
breaking image.



Translation to ASM.rar (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Mathieu SUEN
Why do you have this special syntaxe? Why don't you use the Smalltalk  
bytcode?

        Mth



On May 7, 2007, at 12:54 PM, sig wrote:

> ((block 1
>  (mov 1 't2')
>  (mov 2 't3')
>  (add 't3' 't2')
>  (jge block5))
> (block 2
>  (mov 5 't1')
>  (sub 't3' 1)
>  (jnz block4))
> (block 3
>  (mov (mov 10 't1') 't5'))
> (block 4
>  (mov 't5' 't4'))
> (block 5
>  (return 't1')))


Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
On 07/05/07, Mathieu Suen <[hidden email]> wrote:
> Why do you have this special syntaxe? Why don't you use the Smalltalk
> bytcode?
>
because a set of asm instructions is very small.
And this syntax reflects them, nothing more, nothing less. I left a
way for possible extensions/replacement - you can supply own class
with instruction set to parser.
And external libraries don't know how to deal with smallints/oops.
They understand only raw values and pointers to data.

As for bytecode you already having Exupery. But it will generate an
assembly which targeted for using with oops (tagged integers
everywhere, e.t.c).
My generator acting with variables/values as with registers, not oops.
That's why i called the topic 'Everything is a Register'.

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
and in addition, a simple example why i'm not using a smalltalk
standart selectors.

for loading a value via indirect pointer you might put with my syntax:

val := b loadDword loadDword.  "   load value from memory location
pointed by b, then load value pointed by value  "

same , but using smalltalk standart selectors:

val := self at: (self at: b) .

more complex case:

val := (b loadDword + 4) loadDword

in smalltalk will look like:

val := self at: (self at: b) + 4 .

---

conditional branching smalltalk:

(a > b ) ifTrue: [] ifFalse:[]

my syntax:

(a cmp: b) ifGreater: [] else: []
or
a = b ifGreater: [] else: []

--
checking for a zero:
( a := b - 1 ) ifZero: [] ..

smalltalk:
a := b - 1.
a = 0 ifTrue: [] ..

--
there also branching selectors like ifCarry, ifOverflow which don't
have a meaning in smalltalk at all.

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Bryce Kampjes
In reply to this post by Mathieu SUEN
Mathieu Suen writes:
 > Why do you have this special syntaxe? Why don't you use the Smalltalk  
 > bytcode?
 > On May 7, 2007, at 12:54 PM, sig wrote:
 >
 > > ((block 1
 > >  (mov 1 't2')
 > >  (mov 2 't3')
 > >  (add 't3' 't2')
 > >  (jge block5))
 > > (block 2
 > >  (mov 5 't1')
 > >  (sub 't3' 1)
 > >  (jnz block4))
 > > (block 3
 > >  (mov (mov 10 't1') 't5'))
 > > (block 4
 > >  (mov 't5' 't4'))
 > > (block 5
 > >  (return 't1')))

The format shown is just a written form of Exupery's low level
intermediate. It was originally created for unit testing, it can
be used to create intermediate objects, to compare outupt, and
to set up mocks.

In normal operation, Exupery will translate bytecode through several
intermediate forms to create tolerably efficient machine code.

Bryce

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
lol.. i missed the collapsed quoted text and thought that Mathieu
complaining about smalltalk syntax given in example, not intermediate
form. :)))

No, Mathieu, you'll write an asm routine as regular smalltalk method,
just using special set of selectors :)
Everything else is not your problem.

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Mathieu SUEN
On May 7, 2007, at 2:50 PM, sig wrote:

> lol.. i missed the collapsed quoted text and thought that Mathieu
> complaining about smalltalk syntax given in example, not intermediate
> form. :)))

Not complaining juste asking :)

>
> No, Mathieu, you'll write an asm routine as regular smalltalk method,
> just using special set of selectors :)
> Everything else is not your problem.
>


You can take a look at the NewCompiler you can write somthings like:

        | iRMethod aCompiledMethod |
        iRMethod := IRBuilder new
                numRargs: 1;
                addTemps: #(self); "receiver and args declarations"
                pushLiteral: $e;
                returnTop;
                ir.

        aCompiledMethod := iRMethod compiledMethod.
        aCompiledMethod valueWithReceiver: nil arguments: #()

        Mth

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
On 07/05/07, Mathieu Suen <[hidden email]> wrote:
> On May 7, 2007, at 2:50 PM, sig wrote:
>
> > lol.. i missed the collapsed quoted text and thought that Mathieu
> > complaining about smalltalk syntax given in example, not intermediate
> > form. :)))
>
> Not complaining juste asking :)
>
sorry, my English is bad :)

> You can take a look at the NewCompiler you can write somthings like:
>
>         | iRMethod aCompiledMethod |
>         iRMethod := IRBuilder new
>                 numRargs: 1;
>                 addTemps: #(self);              "receiver and args declarations"
>                 pushLiteral: $e;
>                 returnTop;
>                 ir.
>
>         aCompiledMethod := iRMethod compiledMethod.
>         aCompiledMethod valueWithReceiver: nil arguments: #()
>

well this will produce a CompiledMethod instance. I am right?
Maybe i was unclear in explaining what my generator produces? It not
produces bytecode for squeak VM. It produces bytecode for PC CPU, also
known as assembler instructions.
You can't run them from squeak directly, a special plugin/primitive
will be required to do so.
If your PC CPU understands ST-80 bytecode then my generator is useless.

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Herbert König
In reply to this post by Igor Stasenko
Hello Sig,

s> My explo[it]ration of Exupery brings some fruits - an assembler
s> generator using smalltalk syntax. :)

I like that very much but I didn't manage to find out
- who will translate the assembler into actual X86 machine code
- how to run the generated code from Squeak.

Am I being dense?

Me having still one leg in a world where I replaced C-code by
handwritten assembler to speed up digital signal processing :-))

Cheers,

Herbert                            mailto:[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
On 07/05/07, Herbert König <[hidden email]> wrote:
> Hello Sig,
>
> s> My explo[it]ration of Exupery brings some fruits - an assembler
> s> generator using smalltalk syntax. :)
>
> I like that very much but I didn't manage to find out
> - who will translate the assembler into actual X86 machine code
> - how to run the generated code from Squeak.
>
I'm not finished yet. It require to perform few additional steps to
produce final code: replace returns and add prologue/epilogue to
function corresponding to supplied calling convention.
In case if you using a local calls, there also need to keep track
relocation points, to replace them by concrete absolute address values
when code is placed in fixed memory (Exupery have this already, i just
didn't developped to that point).

In any case you need an Exupery to produce final code, and
ExuperyPlugin if you want to install and run it.
You'd better ask Bryce about that, i don't know details yet (have to
dig details). It may require to add few primitives especially designed
to run my pure assembly.

Or you can write own plugin, which i not recommend to do (Increasing a
code written in C is the worst solution as for me :) ). Its simple
enough to implement by own: allocate fixed system memory with
execution permission, place generated code there and return a pointer
to function entry point. Then you can use FFI to run the code.
Also, some trickery can be used to register the function as primitive.

The consequences of running pure assembler of course laying on solely
on the author. There a high risk that buggy assembler code will
attempt to access protected memory or broke C stack using incorrectly
set calling convention.
But these risks get rewarded considerably :)

> Am I being dense?
>
> Me having still one leg in a world where I replaced C-code by
> handwritten assembler to speed up digital signal processing :-))
>

I'm greatly inspired by Ian Pumiatra COLA/Pepsi project. I want to
free from shackles of C.

Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

J J-6
In reply to this post by Mathieu SUEN
>From: Mathieu Suen <[hidden email]>
>Reply-To: The general-purpose Squeak developers
>list<[hidden email]>
>To: The general-purpose Squeak developers
>list<[hidden email]>
>Subject: Re: Everything is a Register!
>Date: Mon, 7 May 2007 15:08:49 +0200
>
>You can take a look at the NewCompiler you can write somthings like:
>
> | iRMethod aCompiledMethod |
> iRMethod := IRBuilder new
> numRargs: 1;
> addTemps: #(self); "receiver and args declarations"
> pushLiteral: $e;
> returnTop;
> ir.
>
> aCompiledMethod := iRMethod compiledMethod.
> aCompiledMethod valueWithReceiver: nil arguments: #()
>
> Mth

But this is talking to the Smalltalk VM, which is a stack machine.  He is
trying to write directly to the host CPU, which is more register oriented.

_________________________________________________________________
Download Messenger. Join the i’m Initiative. Help make a difference today.
http://im.live.com/messenger/im/home/?source=TAGHM_APR07


Reply | Threaded
Open this post in threaded view
|

Re: Everything is a Register!

Igor Stasenko
well, IRBuilder can be used too :)
Suppose you wrote a class, which methods is solely in asm.
Then, adding something like this in your class will do funny trick:

MyClass class>>new
| gen |
    self isAlreadyWrapped ifTrue: [  ^ self basicNew ].
    gen := AsmGenerator new createAssemblyFor: self.  " compile
instance methods and prepare them for use"
    gen GenerateWrappersFor: self
    ^ self basicNew
---

A GenerateWrappersFor must do the following: generate a CompiledMethod
for each method in class which actually wraps call to assembler
function, and replace a method in MyClass methods dictionary.

As result you get an easy and transparent form for calling your asm code.

instance := MyClass new.  "create an instance, and have fun"
instance myAsmRoutine1: 5 with: 10 ...  "call an assemler method via wrapper "


On 07/05/07, J J <[hidden email]> wrote:

> >From: Mathieu Suen <[hidden email]>
> >Reply-To: The general-purpose Squeak developers
> >list<[hidden email]>
> >To: The general-purpose Squeak developers
> >list<[hidden email]>
> >Subject: Re: Everything is a Register!
> >Date: Mon, 7 May 2007 15:08:49 +0200
> >
> >You can take a look at the NewCompiler you can write somthings like:
> >
> >       | iRMethod aCompiledMethod |
> >       iRMethod := IRBuilder new
> >               numRargs: 1;
> >               addTemps: #(self);              "receiver and args declarations"
> >               pushLiteral: $e;
> >               returnTop;
> >               ir.
> >
> >       aCompiledMethod := iRMethod compiledMethod.
> >       aCompiledMethod valueWithReceiver: nil arguments: #()
> >
> >       Mth
>
> But this is talking to the Smalltalk VM, which is a stack machine.  He is
> trying to write directly to the host CPU, which is more register oriented.
>
> _________________________________________________________________
> Download Messenger. Join the i'm Initiative. Help make a difference today.
> http://im.live.com/messenger/im/home/?source=TAGHM_APR07
>
>
>