Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2019-12

Object/Pointer Swap Intrinsic

5 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

J. Gareth Moreton

Hi everyone,

I was wondering... is there an intrinsic in Free Pascal that swaps the pointers stored in two object or pointer variables? That is... something like "procedure SwapAddresses(var Obj1: TObject; var Obj2: TObject);" so after it is called, Obj2 now points to Obj1 and vice versa?  Under x86-64, for example, it can be implemented as (Intel notation):

XOR RCX, RDX
XOR RDX, RCX
XOR RCX, RDX

Or just

XCHG RCX, RDX

Both methods take just 3 cycles to perform (faster than transferring the object data by several orders of magnitude, plus the pointers don't get dereferenced).  But equivalent Pascal code that typecasts the objects or pointers into PtrUint and then uses the xor operator may not be portable (e.g. on platforms that don't have pointers and treat objects differently).

I ask this because I've noticed a slightly clever speed-up in parts of the peephole optimiser where "TmpUsedRegs" contains exactly the information required to be stored in "UsedRegs" (usually because "UpdateUsedRegs(TmpUsedRegs, tai(p.Next))" was called and then p was freed, hence any required call to "UpdateUsedRegs(tai(p.Next))" will reproduce the same register usage.  By simply swapping the pointers between UsedRegs and TmpUsedRegs, I can immediately treat the contents of TmpUsedRegs as the live data and repurpose UsedRegs as the new temporary register tracking.  Calls to TransferUsedRegs and RestoreUsedRegs are slow.

Gareth aka. Kit

Reply by email

J. Gareth Moreton
to J. Gareth Moreton

Of course, I briefly forgot that UsedRegs and TmpUsedRegs aren't objects, but arrays of objects - the same principle still applies though to their members.

J. Gareth Moreton wrote 41 lines
Hi everyone, I was wondering... is there an intrinsic in Free Pascal that swaps the pointers stored in two object or pointer variables? That is... something like "procedure SwapAddresses(var Obj1: TObject; var Obj2: TObject);" so after it is called, Obj2 now points to Obj1 and vice versa?  Under x86-64, for example, it can be implemented as (Intel notation): XOR RCX, RDX XOR RDX, RCX XOR RCX, RDX Or just XCHG RCX, RDX Both methods take just 3 cycles to perform (faster than transferring the object data by several orders of magnitude, plus the pointers don't get dereferenced).  But equivalent Pascal code that typecasts the objects or pointers into PtrUint and then uses the xor operator may not be portable (e.g. on platforms that don't have pointers and treat objects differently). I ask this because I've noticed a slightly clever speed-up in parts of the peephole optimiser where "TmpUsedRegs" contains exactly the information required to be stored in "UsedRegs" (usually because "UpdateUsedRegs(TmpUsedRegs, tai(p.Next))" was called and then p was freed, hence any required call to "UpdateUsedRegs(tai(p.Next))" will reproduce the same register usage.  By simply swapping the pointers between UsedRegs and TmpUsedRegs, I can immediately treat the contents of TmpUsedRegs as the live data and repurpose UsedRegs as the new temporary register tracking.  Calls to TransferUsedRegs and RestoreUsedRegs are slow. Gareth aka. Kit _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Sven Barth
to J. Gareth Moreton: I was wondering... is there an intrinsic in Free Pascal that swaps the pointers stored in…
J. Gareth Moreton wrote 16 lines
Hi everyone, I was wondering... is there an intrinsic in Free Pascal that swaps the pointers stored in two object or pointer variables? That is... something like "procedure SwapAddresses(var Obj1: TObject; var Obj2: TObject);" so after it is called, Obj2 now points to Obj1 and vice versa?  Under x86-64, for example, it can be implemented as (Intel notation): XOR RCX, RDX XOR RDX, RCX XOR RCX, RDX Or just XCHG RCX, RDX

It might be more useful to try to write high level optimization that detects the typical swap sequence of

tmp := a;
a := b;
b := tmp;

And optimizes that to the most optimal CPU instructions (by converting it to an internal "Swap" intrinsic, similar as it is done for the load/modify/store optimizations).

Then any existing code would profit from that as well.

And for your specific use case you could then add such swap procedures to cutils.pas or so...

Regards,
Sven

Reply by email

J. Gareth Moreton
to Sven Barth

That's true.  Given I specialise in optimisation, I've started to venture towards the node level to see where improvements can be made.

One question I do have in that regard... are platform-specific nodes allowed? What I mean is, for example, a node's 'simplify' routine may transmute a set of nodes to a platform-specific node that may better benefit, say, vectorisation on an AMD64 processor.  (A swap node will be platform-independent, and if platform-specific assembly isn't available, then to just create the equivalent Pascal code as you laid out below).

So many exciting challenges ahead!  Got to fix bugs in the existing stuff first though.

Gareth aka. Kit

Sven Barth wrote 40 lines
Am 11.12.2019 um 07:26 schrieb J. Gareth Moreton: > Hi everyone, > > I was wondering... is there an intrinsic in Free Pascal that swaps > the pointers stored in two object or pointer variables? That is... > something like "procedure SwapAddresses(var Obj1: TObject; var Obj2: > TObject);" so after it is called, Obj2 now points to Obj1 and vice > versa?  Under x86-64, for example, it can be implemented as (Intel > notation): > > XOR RCX, RDX > XOR RDX, RCX > XOR RCX, RDX > > Or just > > XCHG RCX, RDX It might be more useful to try to write high level optimization that detects the typical swap sequence of tmp := a; a := b; b := tmp; And optimizes that to the most optimal CPU instructions (by converting it to an internal "Swap" intrinsic, similar as it is done for the load/modify/store optimizations). Then any existing code would profit from that as well. And for your specific use case you could then add such swap procedures to cutils.pas or so... Regards, Sven _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Sven Barth
to J. Gareth Moreton
J. Gareth Moreton wrote 10 lines
That's true.  Given I specialise in optimisation, I've started to venture towards the node level to see where improvements can be made. One question I do have in that regard... are platform-specific nodes allowed? What I mean is, for example, a node's 'simplify' routine may transmute a set of nodes to a platform-specific node that may better benefit, say, vectorisation on an AMD64 processor.  (A swap node will be platform-independent, and if platform-specific assembly isn't available, then to just create the equivalent Pascal code as you laid out below).

Take a looks for code sequences that
can be converted into load/modify/store instructions. For that purpose it converts the nodes to a new tinlinenode with e.g. in_ror_assign_x_y which is handled by tcginlinenode.second_AndOrXorShiftRot_assign. This method creates platform independent assembly code. For platform specific code you'd overwrite e.g. tx8664inlinenode.second_AndOrXorShiftRot_assign.

A similar approach would for the Swap optimization.

Regards,
Sven

Reply by email