[fpc-devel] Aligned array feature
J. Gareth Moreton
gareth at moreton-family.com
Wed Apr 13 01:12:25 CEST 2022
In the case of a record type (which already exists), "align 16" ensures
the whole thing is aligned on a 16-byte boundary, not the individual
elements. Generally it's not something to be to worried about, but in
some special cases, such alignment is important (e.g. some of the SSE
and AVX assembly instructions).
In regards to packed records... theoretically it just makes sure that
there are no filler bytes in between elements even though it might cause
less than ideal performance; e.g. a packed record with B: Byte; and I:
Integer; fields in that order will result in the Integer field not being
on a 4-byte boundary, sometimes requiring more complicated machine code
to read and write to it. Using SSE/AVX as an example again, an aligned,
packed record would be required in the following circumstance:
type TAlignedSingleVector = packed record
X, Y, Z, W: Single;
end align 16;
Under x86_64 at least, not specifying 'packed' will put each element on
an 8-byte boundary rather than a 4-byte boundary (the size of Single).
When packed together like this, a variable of this type can be passed
into an XMM register via MOVAPS - if it's not aligned to a 16-byte
boundary, an access violation will occur (if you can't guarantee
alignment, you have to use MOVUPS instead, which is slower on some
platforms), and if it's not packed, then only the first two fields get
written into the XMM register due to the padding in between.
However, Embarcardo Delphi (which supports aligned records) is very
unclear as to what happens if a record is both packed and aligned -
syntactically it's allowed, but it's not clear if the resultant record
is byte-aligned or 16-byte-aligned. This might need testing, although
personally I feel that 'align 16' should take precedence since it's very
explicit and, in some implementatiosn (if not all), the record is
aligned to the natural alignment of the first element... so with the
above TAlignedSingleVector, it's aligned to a 4-byte boundary. This
goes out the window though when dealing with an array of such records
when the size is not a multiple of the alignment. Come to think of it,
there's a lot of conformance testing to be done, and defining behaviour
in more unusual circumstances, such as when you have a packed record and
one of the elements is of an aligned type. I'll need to start writing
up a question sheet!
In the case of something like "type TAlignedVector = array[0..3] of
Single align 16;", the individual elements are still packed as expected
(I think... I know packed arrays are a thing), but the entire thing (or
equivalently, element 0) is on a 16-byte boundary. My reasoning for
supporting such arrays is that it maps directly with __m128 and the
like. Strictly speaking, __m128 etc. are opaque types, but are
implemented as arrays internally, although they're currently bugged in
Free Pascal in that they're not aligned. I submitted a fix for that
here - https://gitlab.com/freepascal.org/fpc/source/-/merge_requests/193
- although I found a whole other host of problems afterwards. Originally
I started piling on the changes and fixes, but since it's still a work
in progress, I stripped everything out except what was advertised...
making __m128 etc. aligned.
My current question though is regarding testing. Writing tests for
these aligned arrays and records is simple enough, but I'm not sure what
subdirectory/class they fall under... tbs or test/cg etc.
Gareth aka. Kit
On 12/04/2022 23:27, Karoly Balogh wrote:
> On Tue, 12 Apr 2022, J. Gareth Moreton via fpc-devel wrote:
>> To complement aligned records, I'm trying out an implementation of
>> aligned records. Like how you might declare an aligned record as follows:
>> type AlignedVector = packed record
>> X, Y: Double;
>> end align 16;
> Is this "aligned records" a new language feature already implemented, or
> it's only being proposed? What is the result of the above syntax?
> It's very confusing that it's both a "packed" and an "aligned" record.
>> Of course, that assumes such alignment support is okay in the eyes of
>> the core team (I'll need to double-check what Delphi supports so it's
>> enabled or disabled as appropriate under $MODE DELPHI).
> Well, it depends on what "align 16" would do in these cases. Only change
> the alignment between the fields/elements of the record and array? Or try
> to guarantee the alignment of the array and the record itself? The later
> might be extremely tricky to provide in a reliable and platform
> independent way, as for global variables it might depend on the behavior
> of linkers, OS loaders, and so on, and for heap variables it will depend
> on the alignment the heap allocator supports. (Although we can extend the
> heap allocator to support aligned allocations, but I'm still not a fan.)
> And for just changing the alignment inside the array/record I think it's
> too big of a syntax mess for too little benefit, which is just waiting for
> abuse, and to be a source of hard to track down bugs.
This email has been checked for viruses by Avast antivirus software.
More information about the fpc-devel