Sign in Join

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

Mailing lists / fpc-devel / 2020-04

Rules about record types and internal storage

11 messages · 3 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'm just trying to get properly versed with the rules of record types over here: https://www.freepascal.org/docs-html/ref/refsu15.html

For standard record types (no "packed" modifier or compiler directives or anything), I'm wondering how many liberties that the compiler is allowed to take in storing its data.  Take the following example (from raybench.pas over here: http://runtimeterror.com/tools/raybench ):

type
   Vec = record
     X, Y, Z: Single;
   end;
function VLength(const V: Vec): Single;
begin
   Result:=Sqrt(V.X*V.X + V.Y*V.Y + V.Z*V.Z);
end;

If you wanted to get the highest speed possible for this routine on an Intel processor, one solution would be to pack X, Y and Z together, have an invisible 4th dummy field, and align the entire record to a 16 byte boundary, because then you could pass the entire record by value through an XMM register and the VLength operation can be performed with just a pair of VDPPS (dot product) and VSQRTSS (square root) instructions.

Obviously if you use 'packed record' or a compiler directive to change things up, this may not be possible, but at what points is the compiler allowed to make its own choice on what might be best?

Gareth aka. Kit

P.S. Of course you can force it by forcing the vector to be an m128 type and specifying vectorcall for x86_64-win64, but not everyone will know to do that and it gets unwieldly rather quickly.  Speaking of vectorcall, I'm wondering if we can introduce 'fastcall' as an alias for 'ms_abi_default', mostly so if we follow Microsoft Visual C++'s example of automatically making all routines vectorcall (which is closer to the System V ABI used by linux and will make vectorisation easier), we can force the default one if we need a routine that, say, has to interface with a third-party library ('fastcall' under win32 is what the MS ABI is based off... first parameter in ECX, second in EDX and everything else on the stack).

This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Sven Barth
to J. Gareth Moreton

J. Gareth Moreton schrieb am Do., 2. Apr. 2020,
15:25:

Show quoted text 5 lines
For standard record types (no "packed" modifier or compiler directives or anything), I'm wondering how many liberties that the compiler is allowed to take in storing its data. Take the following example (from raybench.pas over here: http://runtimeterror.com/tools/raybench ):

With no explicit packing specified the compiler in general follows the platform's C compiler for compatibility reasons.

P.S. Of course you can force it by forcing the vector to be an m128 type

Show quoted text 11 lines
and specifying vectorcall for x86_64-win64, but not everyone will know to do that and it gets unwieldly rather quickly. Speaking of vectorcall, I'm wondering if we can introduce 'fastcall' as an alias for 'ms_abi_default', mostly so if we follow Microsoft Visual C++'s example of automatically making all routines vectorcall (which is closer to the System V ABI used by linux and will make vectorisation easier), we can force the default one if we need a routine that, say, has to interface with a third-party library ('fastcall' under win32 is what the MS ABI is based off... first parameter in ECX, second in EDX and everything else on the stack).

Please provide a source for your statement that MSVC uses vectorcall by default. Cause I highly doubt that as Microsoft is huge on backwards compatibility especially regarding the lower level stuff.

Regards,
Sven

Reply by email

Sven Barth
to Sven Barth

Sven Barth schrieb am Do., 2. Apr. 2020,
17:10:

Show quoted text 17 lines
P.S. Of course you can force it by forcing the vector to be an m128 type > and specifying vectorcall for x86_64-win64, but not everyone will know > to do that and it gets unwieldly rather quickly. Speaking of > vectorcall, I'm wondering if we can introduce 'fastcall' as an alias for > 'ms_abi_default', mostly so if we follow Microsoft Visual C++'s example > of automatically making all routines vectorcall (which is closer to the > System V ABI used by linux and will make vectorisation easier), we can > force the default one if we need a routine that, say, has to interface > with a third-party library ('fastcall' under win32 is what the MS ABI is > based off... first parameter in ECX, second in EDX and everything else > on the stack). > Please provide a source for your statement that MSVC uses vectorcall by default. Cause I highly doubt that as Microsoft is huge on backwards compatibility especially regarding the lower level stuff.

Just checked myself: cdecl is the default. So nothing needs to be changed here for us.

Regards,
Sven

Reply by email

J. Gareth Moreton
to Sven Barth

Apologies - I wasn't clear.  There is an option in the MSVC compiler to default to vectorcall, but you have to specify it.

Gareth aka. Kit

Sven Barth wrote 41 lines
Sven Barth < > schrieb am Do., 2. Apr. 2020, 17:10: P.S. Of course you can force it by forcing the vector to be an m128 type and specifying vectorcall for x86_64-win64, but not everyone will know to do that and it gets unwieldly rather quickly. Speaking of vectorcall, I'm wondering if we can introduce 'fastcall' as an alias for 'ms_abi_default', mostly so if we follow Microsoft Visual C++'s example of automatically making all routines vectorcall (which is closer to the System V ABI used by linux and will make vectorisation easier), we can force the default one if we need a routine that, say, has to interface with a third-party library ('fastcall' under win32 is what the MS ABI is based off... first parameter in ECX, second in EDX and everything else on the stack). Please provide a source for your statement that MSVC uses vectorcall by default. Cause I highly doubt that as Microsoft is huge on backwards compatibility especially regarding the lower level stuff. Just checked myself: cdecl is the default. So nothing needs to be changed here for us. Regards, Sven _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

J. Gareth Moreton
to J. Gareth Moreton

For a reference, it's the /Gv compiler option:
https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=vs-2019

If anything it's proving to be an interesting study case on how to make something optimal when given code that doesn't give the compiler many clues.  Granted, given the sample function, I'm envisioning some node-level optimisation and auto-inlining.

Gareth aka. Kit

J. Gareth Moreton wrote 60 lines
Apologies - I wasn't clear.  There is an option in the MSVC compiler to default to vectorcall, but you have to specify it. Gareth aka. Kit On 02/04/2020 16:16, Sven Barth via fpc-devel wrote: > Sven Barth < > > schrieb am Do., 2. Apr. 2020, > 17:10: > > P.S. Of course you can force it by forcing the vector to be > an m128 type > and specifying vectorcall for x86_64-win64, but not everyone > will know > to do that and it gets unwieldly rather quickly. Speaking of > vectorcall, I'm wondering if we can introduce 'fastcall' as > an alias for > 'ms_abi_default', mostly so if we follow Microsoft Visual > C++'s example > of automatically making all routines vectorcall (which is > closer to the > System V ABI used by linux and will make vectorisation > easier), we can > force the default one if we need a routine that, say, has to > interface > with a third-party library ('fastcall' under win32 is what > the MS ABI is > based off... first parameter in ECX, second in EDX and > everything else > on the stack). > > > Please provide a source for your statement that MSVC uses > vectorcall by default. Cause I highly doubt that as Microsoft is > huge on backwards compatibility especially regarding the lower > level stuff. > > > Just checked myself: cdecl is the default. So nothing needs to be > changed here for us. > > Regards, > Sven > > > _______________________________________________ > fpc-devel maillist > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> Virus-free. www.avast.com <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient> <#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2> _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

J. Gareth Moreton
to Sven Barth: J. Gareth Moreton schrieb am Do., 2. Apr. 2020, 15:25: With no explicit packing…

Hi Sven,

Am I right in thinking that, for C alignment, each field is aligned according to its data size? For example, if you had:

TType = record
   Field1: Byte
   Field2: LongInt;
end;

Are there are three unused bytes between Field1 and Field2 and the structure as a whole is 8 bytes long and aligned to a 4-byte boundary?  I'm trying to find the page that explains all that, and also exceptional cases where the data size is not necessary the same as the minimum alignment.

Gareth aka. Kit

Sven Barth wrote 47 lines
J. Gareth Moreton < > schrieb am Do., 2. Apr. 2020, 15:25: For standard record types (no "packed" modifier or compiler directives or anything), I'm wondering how many liberties that the compiler is allowed to take in storing its data.  Take the following example (from raybench.pas over here: http://runtimeterror.com/tools/raybench ): With no explicit packing specified the compiler in general follows the platform's C compiler for compatibility reasons. P.S. Of course you can force it by forcing the vector to be an m128 type and specifying vectorcall for x86_64-win64, but not everyone will know to do that and it gets unwieldly rather quickly.  Speaking of vectorcall, I'm wondering if we can introduce 'fastcall' as an alias for 'ms_abi_default', mostly so if we follow Microsoft Visual C++'s example of automatically making all routines vectorcall (which is closer to the System V ABI used by linux and will make vectorisation easier), we can force the default one if we need a routine that, say, has to interface with a third-party library ('fastcall' under win32 is what the MS ABI is based off... first parameter in ECX, second in EDX and everything else on the stack). Please provide a source for your statement that MSVC uses vectorcall by default. Cause I highly doubt that as Microsoft is huge on backwards compatibility especially regarding the lower level stuff. Regards, Sven _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Jonas Maebe
to J. Gareth Moreton
J. Gareth Moreton wrote 10 lines
Am I right in thinking that, for C alignment, each field is aligned according to its data size? For example, if you had: TType = record   Field1: Byte   Field2: LongInt; end; Are there are three unused bytes between Field1 and Field2 and the structure as a whole is 8 bytes long and aligned to a 4-byte boundary?

On most platforms, yes. Probably not on 16 bit platforms.

I'm trying to find the page that explains all that, and also exceptional cases where the data size is not necessary the same as the minimum alignment.

"C alignment" is actually a bad name. It's in fact the ABI alignment (which is indeed what C uses), and hence this is different depending on architecture and OS. As a result, there is no page that explains it all, since you have to look it up in the ABI documentation of every individual platform.

Some examples of non-matching alignments on Darwin/i386:
* double is aligned to 4 bytes
* extended is aligned to 16 bytes

Jonas

Reply by email

J. Gareth Moreton
to Jonas Maebe: https://www.freepascal.org/docs-html/prog/progsu7.html and fpc -h ... -Cc<x> Set…

Hi Jonas,

I brought that up because Florian once asked about just doing everything as vectorcall on Win64 because the calling convention, by and large, is a compatible extension to its default one.  I think issues of compatibility and third-party interfacing makes it not the best idea unless there's a way to override it (which you can do by specifying the 'ms_abi_default' directive, even though that's not the nicest name to remember!)

I'm partly driven by the results from
http://runtimeterror.com/tools/raybench/, thinking "yeah, we can do better than that!".  Speaking of that, I attached the assembler dumps for raybench.pas for comparisons, and it looks like 3.2.0 performs slightly worse in a couple of places, but a number of things have been addressed by 3.3.1 optimisations already (there's an assembler dump for that in the ZIP file too, which also has a load of debug comments).

Gareth aka. Kit

Jonas Maebe wrote 17 lines
On 02/04/2020 17:59, J. Gareth Moreton wrote: > For a reference, it's the /Gv compiler option: > https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=vs-2019 https://www.freepascal.org/docs-html/prog/progsu7.html and fpc -h ... -Cc<x> Set default calling convention to <x> Jonas _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email

Sven Barth
to J. Gareth Moreton

J. Gareth Moreton schrieb am Do., 2. Apr. 2020,
22:33:

Show quoted text 10 lines
Hi Jonas, I brought that up because Florian once asked about just doing everything as vectorcall on Win64 because the calling convention, by and large, is a compatible extension to its default one. I think issues of compatibility and third-party interfacing makes it not the best idea unless there's a way to override it (which you can do by specifying the 'ms_abi_default' directive, even though that's not the nicest name to remember!)

I don't think it's a good idea to change the default calling convention. We'll get many bug reports about third party libraries then even if it can be changed. The potential performance gain is not worth it. And those that want to really optimize their code can do so by adjusting the calling convention either per function or using $calling.

Regards,
Sven

Reply by email

J. Gareth Moreton
to Sven Barth

Agreed.  Sometimes it is a question of how much should be left to the compiler and how much should be left to the programmer when it comes to optimisation.

Gareth aka. Kit

Sven Barth wrote 30 lines
J. Gareth Moreton < > schrieb am Do., 2. Apr. 2020, 22:33: Hi Jonas, I brought that up because Florian once asked about just doing everything as vectorcall on Win64 because the calling convention, by and large, is a compatible extension to its default one.  I think issues of compatibility and third-party interfacing makes it not the best idea unless there's a way to override it (which you can do by specifying the 'ms_abi_default' directive, even though that's not the nicest name to remember!) I don't think it's a good idea to change the default calling convention. We'll get many bug reports about third party libraries then even if it can be changed. The potential performance gain is not worth it. And those that want to really optimize their code can do so by adjusting the calling convention either per function or using $calling. Regards, Sven _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus

Reply by email