Sign in Join

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

Mailing lists / fpc-devel / 2019-03

Re: Successful implementation of inline supportforpureassembler routines on x86

7 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

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

J. Gareth Moreton

I think one of the main issues with intrinsics is that you don't have much control over where results are stored.  Unless you're chaining a load of intrinsics together in a mess of function calls in actual parameters, the result is going to have to be stored in a local variable, which even on good days will end up being stored on the stack, and problems can occur if the stack isn't aligned and you're using SSE or AVX instructions.  After that, when you call the next intrinsic that uses the result, it will have to recall that data from memory.

With care, especially if you only need a temporary value, you don't have to worry about the stack at all or worry in the back of your mind that the intrinsics aren't being as optimal as they could be.  To use the integer clamp function as an example (if x < 0 then x := 0):

{ Microsoft x64 calling convention... X is in ECX } function ClampInt(X: LongInt): LongInt; assembler; nostackframe; inline; asm
  XOR EAX, EAX
  TEST ECX, ECX
  CMOVG EAX, ECX
end;

The instructions are arranged in order to reduce the chance of a pipeline stall, and ECX is written to the result (EAX) only if ECX is greater than zero, otherwise EAX is set to zero (by the XOR EAX, EAX instruction).

True, optimiser improvements can improve a lot of the stall situations and unnecessary storage, but that in itself is a mammoth task.

Gareth aka. Kit

On Sun 17/03/19 21:56 , Florian Klämpfl sent:

J. Gareth Moreton wrote
My take on the whole "inlined assembler routines" vs. "intrinsics"... why not both?

Maintenance effort.

They both fill a different niche,

What niche do inline assembler routines fill, intrinsics dont't ? This is imo the central question. What can be done by inline assembler routines, intrinsics cannot?

Reply by email

Marģers .
to J. Gareth Moreton

 

----- Reply to message -----
Subject: Re: [fpc-devel] Successful implementation of inline supportforpureassembler routines on x86
Date: 2019. gada 18. marts 00:28:10
From: J. Gareth Moreton
To: FPC developers' list

  To use the integer clamp function as an
example (if x < 0 then x := 0):
{ Microsoft x64 calling convention... X is in ECX } function ClampInt(X: LongInt): LongInt;
assembler; nostackframe; inline;
Show quoted text 5 lines
asm   XOR EAX, EAX   TEST ECX, ECX   CMOVG EAX, ECX end;
try code:
y:=0;
if x < 0 then x:=y;

Reply by email

Sven Barth
to J. Gareth Moreton: I think one of the main issues with intrinsics is that you don't have much control over…

J. Gareth Moreton schrieb am So., 17. März
2019, 23:27:

Show quoted text 9 lines
I think one of the main issues with intrinsics is that you don't have much control over where results are stored. Unless you're chaining a load of intrinsics together in a mess of function calls in actual parameters, the result is going to have to be stored in a local variable, which even on good days will end up being stored on the stack, and problems can occur if the stack isn't aligned and you're using SSE or AVX instructions. After that, when you call the next intrinsic that uses the result, it will have to recall that data from memory.

And I believe that this is the advantage of intrinsics, because here the compiler *can* decide to use a different register. Especially if the compiler supports instruction scheduling and such. At work I've worked with AES-NI and I definitively preferred to work with the intrinsics and didn't have to care about what registers to use, because the compiler and optimizer took care of that.
That is something that Pascal should stand for: ease of use. Assembler is not easy to use.

Regards,
Sven

Reply by email

J. Gareth Moreton

I didn't mean for a particular intrinsic to be cross-platform, but implementing intrinsics for every single instruction on a particular platform, and then doing the same for the other platforms supported by Free Pascal - that is, composing intrinsics for the 1000+ instructions on x86_64, testing to see if they properly expand into the assembler commands that they're advertised to do, and then doing the same for ARM etc.  Hence the maintenance factor.

Gareth aka. Kit

On Mon 18/03/19 07:03 , "Sven Barth" sent:
J. Gareth Moreton schrieb am So., 17. März 2019, 22:26: I do have a slight concern when it comes to intrinsic support, because support will be needed to be added for all platforms, (virtually) all instructions and tested to see if they expand into the expected instruction, along with determining what happens when you string several intrinsics together (i.e. passing the result of one such intrinsic into the actual parameter of another).  I want to say that it will require just as much, if not more, maintenance than permitting inlined assembler routines under limited circumstances, including adding intrinsics for every individual platform's assembly language and showing that it works. No, intrinsics can be CPU specific. So if you'd use the intrinsic for AESENC then you'd get a compile time error on non-x86 CPUs. No need to try to implement them for all platforms. 
Regards, Sven 

Reply by email

Marco van de Voort
to Sven Barth: J. Gareth Moreton schrieb am So., 17. März 2019, 23:27: And I believe that this is the…

Op 3/18/2019 om 8:00 AM schreef Sven Barth via fpc-devel:

Show quoted text 9 lines
J. Gareth Moreton < > schrieb am So., 17. März 2019, 23:27: And I believe that this is the advantage of intrinsics, because here the compiler *can* decide to use a different register. Especially if the compiler supports instruction scheduling and such. At work I've worked with AES-NI and I definitively preferred to work with the intrinsics and didn't have to care about what registers to use, because the compiler and optimizer took care of that.

(well, better double check output, it is not always ideal)

I've seen nice examples in simd lib
(http://ermig1979.github.io/Simd/index.html), where they use generics to bundle intrinsics into blocks, and then reuse them multiple times, e.g. 3 times for the first, bulk and last line of an image.

That is something that Pascal should stand for: ease of use. Assembler is not easy to use.

If something is generic enough to be an intrinsic, it should be an intrinsic and as secured as much as possible.

Inlinable assembler however is something to get some of that defining power also in the user's hand. It doesn't really matter that there are border cases, as long as they can be described, since assembler is intrinsically unportable anyway. But having something like that is quite important I think. Though examples come more from my embedded, and less from my PC work (even though I use AVX2 there. Intrinsics would be better for many cases)

Reply by email

J. Gareth Moreton

Well I already decided not to pursue this particular feature any further because of the Holy Grail that are intrinsics.
If Trunc is automatically inlined, why is there a separate implementation of it on x86_64 anyway?
On Sun 24/03/19 12:09 , Florian Klämpfl sent:
...

This is a not a valid reason. You can play with the svn branch. http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel [1]">

Who's going to? No-one's doing to develop real-world examples of the use of intrinsics on an unofficial branch whose address takes some hunting to find.  At least on the SVN trunk, you'll be playing and DEVELOPING with features that are most likely going to stay.  This won't happen with intrinsics until they are merged with the trunk, whenever that will happen.

Heck, with the current branch I can't even compile through Lazarus properly because it gets completely mixed up somewhere with conflicting definitions of TProcessPriority, so testing and development there is limited even further.
Gareth aka. Kit

Links:
------
[1] http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Florian Klämpfl
to J. Gareth Moreton
J. Gareth Moreton wrote
If Trunc is automatically inlined, why is there a separate implementation of it on x86_64 anyway?

Probably when optimizing for size on x86_64-linux (where extended is no deprecated) and if sse3 is no enabled.

Reply by email