[cfe-dev] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

James Y Knight via cfe-dev cfe-dev at lists.llvm.org
Mon Aug 24 09:28:46 PDT 2020


Making a change like that privately while you're working through the list
of callers could be a useful strategy to help keep track of which callers
you've checked for correctness already. It might even be useful to send in
a draft review, to ask for help in determining which of these callsites
should and should not be modified.

But I don't think it'd be useful to actually check that change in.

I currently would expect that the vast majority of the time, the code
is correct to be using the guaranteed "ABI" alignment, and only a small
number of places need to be changed to use the preferred type alignment.


On Thu, Aug 20, 2020 at 5:50 PM Xiangling Liao <xiangxdh at gmail.com> wrote:

> Thank you for your explanation. They are very helpful. I agree that we
> should only use "PreferredAlignment" for creating a complete object. I will
> create a phabricator patch later based on our discussions here for reviews.
>
>
>
> And due to migration reasons, we would still propose adding an extra flag
> without default argument instead like the following:
>
>
>
> /// Set "NeedsPreferredAlignment" as true only when allocating memory for
> a variable on
>
> /// the stack or in global/thread local memory. The preferred alignment
> applies only to a complete
>
> /// object.
>
> CharUnits ASTContext::getTypeAlignInChars(QualType T, *bool
> NeedsPreferredAlignment*) const {
>    if (*NeedsPreferredAlignment*)
>      return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));
>
>
>
>    return toCharUnitsFromBits(getTypeAlign(T));
> }
>
>
> And in the proposed patch, we will go through "getTypeAlignInChars"
> similar functions case-by-case and pass a value to the flag as needed.
>
>
> By doing this, we would expect developers to consciously know and also
> patch reviewers consciously agree on which alignment needs to be used.
>
>
>
> Later, when we finish the migration process(probably in a few months), we
> may remove the flag and replace the "true" flag with invoking
> "getPreferredTypeAlign" directly.
>
>
> Any opinions on this proposal? Please let me know if there are any
> concerns and suggestions.
>
>
> Thank you,
>
> Xiangling
>
>
>
>
>
> On Thu, Aug 20, 2020 at 12:35 PM David Rector <davrecthreads at gmail.com>
> wrote:
>
>>
>>
>> On Aug 20, 2020, at 9:26 AM, James Y Knight <jyknight at google.com> wrote:
>>
>>
>>
>> On Wed, Aug 19, 2020 at 8:53 PM David Rector <davrecthreads at gmail.com>
>> wrote:
>>
>>> For that matter "preferred alignment" is also confusing.  Who prefers
>>> it?  When might that preference not be met?
>>>
>>> Here is my full understanding so far, expressed in the hope that
>>> pointing out my confusions here might better help answer Xiangling’s
>>> questions below:
>>>
>>>    - The "ABI" alignment of a type = the ABI-guaranteed minimum
>>>    alignment of any object of that type built by any standard-conformant
>>>    compiler.
>>>
>>> Correct, this is the guaranteed alignment of any(***) object of that
>> type (either top-level complete object or a subobject).
>>
>>>
>>>    - The "preferred" alignment of a type = the actual alignment, at
>>>    least as large as the ABI alignment, that *our* compiler will
>>>    *always* use in constructing an object of that type.
>>>
>>> When constructing a global or local variable, yes, we do.
>>
>>>
>>>    - Therefore, whenever we are dealing with an object we know *our*
>>>    compiler has constructed, we can use the "preferred" alignment.
>>>       - And thereby take advantage of target-specific optimizations
>>>       like AIX.
>>>    - However, whenever we are dealing with e.g. a pointer to an object
>>>    we are not sure we built — i.e. which may have been constructed within a
>>>    function not compiled by our compiler (e.g. a function compiled without AIX
>>>    in some library might have constructed that object and passed a pointer to
>>>    it to some function our compiler is presently building) -- we are forced to
>>>    use only the ABI-guaranteed minimum alignment.
>>>       - `-And thereby miss out on AIX.
>>>
>>> The most critical difference isn't really our compiler vs someone else's
>> compiler. The "preferred" alignment is actually part of the ABI, too (yet
>> another reason why "ABI alignment" is an awful name, and "guaranteed
>> alignment" is better).
>>
>> The preferred alignment applies only to creation of a full object, not,
>> for example, to fields within a struct. E.g. on x86-32:
>>    struct Foo { int i; double d; };
>> the double is placed at offset 4 within the struct, not 8. So, on x86-32,
>> when we have a pointer than could be pointing to such an object, we must
>> only assume the pointee has alignment of 4, not 8.
>>
>>>
>>>    - Whenever a type has alignas(N), that alignment will be returned
>>>    for…both the ABI and the preferred alignments?  It will override both?  Is
>>>    that right?  I recall it overrides the preferred alignment in Xiangling’s
>>>    implementation, at least, not sure about the ABI case.
>>>
>>> Yes. Except that alignas can never reduce the alignment below the
>> guaranteed alignment according to the C/C++ language rules, so in effect it
>> can only override preferred alignment. (The nonstandard
>> `__attribute__((aligned))` and `__attribute__((packed))` can reduce
>> alignment below the default abi alignment, and in that case, you do
>> override both.)
>>
>>>
>>>    - alignof(T) / __alignof(T) must return the "ABI" and "preferred"
>>>    alignments of T, respectively.
>>>
>>> Yep.
>>
>> ***: Of course, with the nonstandard packed/aligned attributes, you can
>> create objects which violate these alignment guarantees. If you do so, you
>> must be extremely careful to only access such an object through the
>> appropriately attributed type, and not through a normal unadorned pointer.
>>
>>
>> Thank you for this great explanation.  I agree that calling the
>> minimum-guaranteed alignment the "ABI" alignment is a big source of
>> confusion.
>>
>> It sounds like Xiangling’s most feasible option is to change dynamic
>> memory allocation to build objects using their preferred alignment, but
>> perhaps that may not have any great effect since the minimum alignment used
>> in such cases is already quite high (8 or 16 as you say).
>>
>> To the extent their are benefits to accessing a pointee using its
>> "preferred" vs. "ABI" alignment, perhaps Xiangling and the rest of us would
>> benefit from a new attribute which guarantees either that, if a particular
>> type is ever placed within an aggregate, that subobject is aligned
>> according to its preferred alignment (i.e., as if it were not in an
>> aggregate at all).
>>
>> This could either be a class attribute applied to every instance, e.g.
>> struct __attribute__((preferred_aligned)) Foo {…};
>>
>> Or to support it built in types too it could be enforced as a type
>> qualifier on variables/parameters a la "const", e.g.
>> ```
>> void f(__attribute__((preferred_aligned)) double *d,
>>        __attribute__((preferred_aligned)) Foo *f);
>> ```
>>
>> For any type so qualified, we could always use its preferred alignment,
>> as Xiangling wishes.
>>
>> Of course by solving the potential-subobject problem we would then have
>> to confront the interfacing-with-other-compilers problem, but if they were
>> assumed to play along, perhaps there could be significant benefits.
>>
>> I’m sure I'm still missing something but in any case I look forward to
>> seeing how this is resolved -- thanks James and good luck Xiangling,
>>
>> Dave
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200824/b2e94f81/attachment-0001.html>


More information about the cfe-dev mailing list