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

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

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

Hubert Tong via cfe-dev

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:


CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}


So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}


Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.


 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}


An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };



Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao



_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
Agree with Eli -- please specify what the other cases are that need to change, besides the alignment used for "new".

On Wed, Aug 12, 2020 at 2:46 PM Eli Friedman <[hidden email]> wrote:

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

1. "a real name is more readable"

Hi Eli, could you elaborate a little more on what real name you are expecting?

 

2. "I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment."

 

Based on the comment on `getTypeAlignInChars`, "Return the ABI-specified alignment of a type, in characters. This method does not work on incomplete types.", I believe `getTypeAlignInChars` and all other three functions I mentioned earlier(which have similar comments) are designed for getting ABI alignment. And these functions are used pervasively in Clang code.  So we need to fix all the places where an "AIX preferred" alignment is wanted when the target defaults to AIX power alignment. And the problem we are trying to deal with is how do we fix those alignment issues. So far we can think of:

 

1) Replace "getTypeAlign" with the following all over the places(which I think this chunk would make the code a bit ugly, and also has migration risk)

 

DefaultsToAIXPowerAlignment

        ? getPreferredTypeAlign

         : getTypeAlign

2) Wrap above with a new function with migration risk as I stated before

3) Add a flag as I stated before

 

Any other ideas are also welcome.

3. “please specify what the other cases are that need to change

The usage of those functions are way too many to be listed all here(probably at least 50 spots), so I just picked several residing on the common path for all targets.

 

Eg.1:

<lib/Sema/SemaChecking.cpp>

static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {

  // See if we can compute the alignment of a VarDecl and an offset from it.

  Optional<std::pair<CharUnits, CharUnits>> P =

      getBaseAlignmentAndOffsetFromPtr(E, S.Context);

 

  if (P)

    return P->first.alignmentAtOffset(P->second);

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

Eg.2:

<lib/Sema/SemaChecking.cpp>

void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {

  E = E->IgnoreParens();

  if (!T->isPointerType() && !T->isIntegerType())

    return;

  if (isa<UnaryOperator>(E) &&

      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {

    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();

    if (isa<MemberExpr>(Op)) {

      auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));

      if (MA != MisalignedMembers.end() &&

          (T->isIntegerType() ||

           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||

                                   Context.getTypeAlignInChars(

                                       T->getPointeeType()) <= MA->Alignment))))

        MisalignedMembers.erase(MA);

    }

  }

}

 

Eg.3:

< lib/CodeGen/CGOpenMPRuntime.cpp>

Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {

  CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);

  unsigned Reserved2Flags = getDefaultLocationReserved2Flags();

  ...

}

 

Eg.4:

< lib/CodeGen/CGAtomic.cpp>

static void

AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,

                  bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,

                  SourceLocation Loc, CharUnits SizeInChars) {

  if (UseOptimizedLibcall) {

    // Load value and pass it to the function directly.

    CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);

...

}

 

Eg.5:

< lib/CodeGen/TargetInfo.cpp>

ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByVal,

                                            bool Realign,

                                            llvm::Type *Padding) const {

  return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByVal,

                                 Realign, Padding);

}


Thank you,

Xiangling


On Wed, Aug 12, 2020 at 3:08 PM James Y Knight <[hidden email]> wrote:
Agree with Eli -- please specify what the other cases are that need to change, besides the alignment used for "new".

On Wed, Aug 12, 2020 at 2:46 PM Eli Friedman <[hidden email]> wrote:

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
ping.

On Wed, Aug 12, 2020 at 5:26 PM Xiangling Liao <[hidden email]> wrote:

1. "a real name is more readable"

Hi Eli, could you elaborate a little more on what real name you are expecting?

 

2. "I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment."

 

Based on the comment on `getTypeAlignInChars`, "Return the ABI-specified alignment of a type, in characters. This method does not work on incomplete types.", I believe `getTypeAlignInChars` and all other three functions I mentioned earlier(which have similar comments) are designed for getting ABI alignment. And these functions are used pervasively in Clang code.  So we need to fix all the places where an "AIX preferred" alignment is wanted when the target defaults to AIX power alignment. And the problem we are trying to deal with is how do we fix those alignment issues. So far we can think of:

 

1) Replace "getTypeAlign" with the following all over the places(which I think this chunk would make the code a bit ugly, and also has migration risk)

 

DefaultsToAIXPowerAlignment

        ? getPreferredTypeAlign

         : getTypeAlign

2) Wrap above with a new function with migration risk as I stated before

3) Add a flag as I stated before

 

Any other ideas are also welcome.

3. “please specify what the other cases are that need to change

The usage of those functions are way too many to be listed all here(probably at least 50 spots), so I just picked several residing on the common path for all targets.

 

Eg.1:

<lib/Sema/SemaChecking.cpp>

static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {

  // See if we can compute the alignment of a VarDecl and an offset from it.

  Optional<std::pair<CharUnits, CharUnits>> P =

      getBaseAlignmentAndOffsetFromPtr(E, S.Context);

 

  if (P)

    return P->first.alignmentAtOffset(P->second);

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

Eg.2:

<lib/Sema/SemaChecking.cpp>

void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {

  E = E->IgnoreParens();

  if (!T->isPointerType() && !T->isIntegerType())

    return;

  if (isa<UnaryOperator>(E) &&

      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {

    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();

    if (isa<MemberExpr>(Op)) {

      auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));

      if (MA != MisalignedMembers.end() &&

          (T->isIntegerType() ||

           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||

                                   Context.getTypeAlignInChars(

                                       T->getPointeeType()) <= MA->Alignment))))

        MisalignedMembers.erase(MA);

    }

  }

}

 

Eg.3:

< lib/CodeGen/CGOpenMPRuntime.cpp>

Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {

  CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);

  unsigned Reserved2Flags = getDefaultLocationReserved2Flags();

  ...

}

 

Eg.4:

< lib/CodeGen/CGAtomic.cpp>

static void

AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,

                  bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,

                  SourceLocation Loc, CharUnits SizeInChars) {

  if (UseOptimizedLibcall) {

    // Load value and pass it to the function directly.

    CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);

...

}

 

Eg.5:

< lib/CodeGen/TargetInfo.cpp>

ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByVal,

                                            bool Realign,

                                            llvm::Type *Padding) const {

  return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByVal,

                                 Realign, Padding);

}


Thank you,

Xiangling


On Wed, Aug 12, 2020 at 3:08 PM James Y Knight <[hidden email]> wrote:
Agree with Eli -- please specify what the other cases are that need to change, besides the alignment used for "new".

On Wed, Aug 12, 2020 at 2:46 PM Eli Friedman <[hidden email]> wrote:

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
In reply to this post by Hubert Tong via cfe-dev
It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

Are you saying you think all 5 of these examples should be using the AIX preferred alignment? Or are you just listing locations that call getTypeAlign and therefore need to be examined?


On Wed, Aug 12, 2020, 5:26 PM Xiangling Liao <[hidden email]> wrote:

1. "a real name is more readable"

Hi Eli, could you elaborate a little more on what real name you are expecting?

 

2. "I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment."

 

Based on the comment on `getTypeAlignInChars`, "Return the ABI-specified alignment of a type, in characters. This method does not work on incomplete types.", I believe `getTypeAlignInChars` and all other three functions I mentioned earlier(which have similar comments) are designed for getting ABI alignment. And these functions are used pervasively in Clang code.  So we need to fix all the places where an "AIX preferred" alignment is wanted when the target defaults to AIX power alignment. And the problem we are trying to deal with is how do we fix those alignment issues. So far we can think of:

 

1) Replace "getTypeAlign" with the following all over the places(which I think this chunk would make the code a bit ugly, and also has migration risk)

 

DefaultsToAIXPowerAlignment

        ? getPreferredTypeAlign

         : getTypeAlign

2) Wrap above with a new function with migration risk as I stated before

3) Add a flag as I stated before

 

Any other ideas are also welcome.

3. “please specify what the other cases are that need to change

The usage of those functions are way too many to be listed all here(probably at least 50 spots), so I just picked several residing on the common path for all targets.

 

Eg.1:

<lib/Sema/SemaChecking.cpp>

static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {

  // See if we can compute the alignment of a VarDecl and an offset from it.

  Optional<std::pair<CharUnits, CharUnits>> P =

      getBaseAlignmentAndOffsetFromPtr(E, S.Context);

 

  if (P)

    return P->first.alignmentAtOffset(P->second);

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

Eg.2:

<lib/Sema/SemaChecking.cpp>

void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {

  E = E->IgnoreParens();

  if (!T->isPointerType() && !T->isIntegerType())

    return;

  if (isa<UnaryOperator>(E) &&

      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {

    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();

    if (isa<MemberExpr>(Op)) {

      auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));

      if (MA != MisalignedMembers.end() &&

          (T->isIntegerType() ||

           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||

                                   Context.getTypeAlignInChars(

                                       T->getPointeeType()) <= MA->Alignment))))

        MisalignedMembers.erase(MA);

    }

  }

}

 

Eg.3:

< lib/CodeGen/CGOpenMPRuntime.cpp>

Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {

  CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);

  unsigned Reserved2Flags = getDefaultLocationReserved2Flags();

  ...

}

 

Eg.4:

< lib/CodeGen/CGAtomic.cpp>

static void

AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,

                  bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,

                  SourceLocation Loc, CharUnits SizeInChars) {

  if (UseOptimizedLibcall) {

    // Load value and pass it to the function directly.

    CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);

...

}

 

Eg.5:

< lib/CodeGen/TargetInfo.cpp>

ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByVal,

                                            bool Realign,

                                            llvm::Type *Padding) const {

  return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByVal,

                                 Realign, Padding);

}


Thank you,

Xiangling


On Wed, Aug 12, 2020 at 3:08 PM James Y Knight <[hidden email]> wrote:
Agree with Eli -- please specify what the other cases are that need to change, besides the alignment used for "new".

On Wed, Aug 12, 2020 at 2:46 PM Eli Friedman <[hidden email]> wrote:

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

On Aug 17, 2020, at 4:06 PM, James Y Knight via cfe-dev <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

Are you saying you think all 5 of these examples should be using the AIX preferred alignment? Or are you just listing locations that call getTypeAlign and therefore need to be examined?

I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave



On Wed, Aug 12, 2020, 5:26 PM Xiangling Liao <[hidden email]> wrote:
1. "a real name is more readable"
Hi Eli, could you elaborate a little more on what real name you are expecting?

 

2. "I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment."

 

Based on the comment on `getTypeAlignInChars`, "Return the ABI-specified alignment of a type, in characters. This method does not work on incomplete types.", I believe `getTypeAlignInChars` and all other three functions I mentioned earlier(which have similar comments) are designed for getting ABI alignment. And these functions are used pervasively in Clang code.  So we need to fix all the places where an "AIX preferred" alignment is wanted when the target defaults to AIX power alignment. And the problem we are trying to deal with is how do we fix those alignment issues. So far we can think of:

 

1) Replace "getTypeAlign" with the following all over the places(which I think this chunk would make the code a bit ugly, and also has migration risk)

 

DefaultsToAIXPowerAlignment
        ? getPreferredTypeAlign
         : getTypeAlign
2) Wrap above with a new function with migration risk as I stated before
3) Add a flag as I stated before

 

Any other ideas are also welcome.
3. “please specify what the other cases are that need to change
The usage of those functions are way too many to be listed all here(probably at least 50 spots), so I just picked several residing on the common path for all targets.

 

Eg.1:
<lib/Sema/SemaChecking.cpp>
static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {
  // See if we can compute the alignment of a VarDecl and an offset from it.
  Optional<std::pair<CharUnits, CharUnits>> P =
      getBaseAlignmentAndOffsetFromPtr(E, S.Context);

 

  if (P)
    return P->first.alignmentAtOffset(P->second);

 

  // If that failed, return the type's alignment.
  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());
}

 

Eg.2:
<lib/Sema/SemaChecking.cpp>
void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
  E = E->IgnoreParens();
  if (!T->isPointerType() && !T->isIntegerType())
    return;
  if (isa<UnaryOperator>(E) &&
      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
    if (isa<MemberExpr>(Op)) {
      auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
      if (MA != MisalignedMembers.end() &&
          (T->isIntegerType() ||
           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
                                   Context.getTypeAlignInChars(
                                       T->getPointeeType()) <= MA->Alignment))))
        MisalignedMembers.erase(MA);
    }
  }
}

 

Eg.3:
< lib/CodeGen/CGOpenMPRuntime.cpp>
Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {
  CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);
  unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
  ...
}

 

Eg.4:
< lib/CodeGen/CGAtomic.cpp>
static void
AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
                  bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
                  SourceLocation Loc, CharUnits SizeInChars) {
  if (UseOptimizedLibcall) {
    // Load value and pass it to the function directly.
    CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);
...
}

 

Eg.5:
< lib/CodeGen/TargetInfo.cpp>
ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByVal,
                                            bool Realign,
                                            llvm::Type *Padding) const {
  return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByVal,
                                 Realign, Padding);
}

Thank you,
Xiangling


On Wed, Aug 12, 2020 at 3:08 PM James Y Knight <[hidden email]> wrote:
Agree with Eli -- please specify what the other cases are that need to change, besides the alignment used for "new".

On Wed, Aug 12, 2020 at 2:46 PM Eli Friedman <[hidden email]> wrote:

I don’t think using a boolean argument is appropriate here; nobody is going to pass in anything other than constant true/false, so a real name is more readable.

 

I guess the question here is what the “default” getTypeAlign means; either it’s the ABI alignment, and we fix all the places that want the “AIX preferred” alignment, or it’s the “AIX preferred” alignment, and we fix all the places that want the ABI alignment.  I think it’s essentially a numbers game: which one is actually more commonly used?  Please give more examples.

 

-Eli

 

From: Xiangling Liao <[hidden email]>
Sent: Wednesday, August 12, 2020 10:56 AM
To: [hidden email]
Cc: [hidden email]; [hidden email]; Eli Friedman <[hidden email]>; James Y Knight <[hidden email]>; Reid Kleckner <[hidden email]>
Subject: [EXT] [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

 

On some targets, preferred alignment is larger than ABI alignment in some cases. For example, on AIX we have special power alignment rules which would cause that. The full discussion details can be found here if interested: http://lists.llvm.org/pipermail/cfe-dev/2020-April/065304.html .

 

Previously, to support those cases, we added a “PreferredAlignment” field in the `RecordLayout` to store the AIX special alignment values in “PreferredAlignment” as the community suggested. It makes sure both `_alignof` and `alignof` return correct values for AIX objects. (The related patch is here: https://reviews.llvm.org/D79719 .)

 

However, that patch alone is not enough. With AIX’s special alignment rule, we need to use “PreferredAlignment” for a majority of the places where ABI alignment are currently used in .

 

Take the cookie size for array new operator calculation for example, the clang invokes `getTypeAlignInChars` to get ABI alignment value:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

                            CGM.getContext().getTypeAlignInChars(elementType));

}

 

So far, we identify that there are 4 functions returning ABI alignment:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Some possible ways we can think of are:

1. Create a new function to be invoked instead, e.g:

/// getTypeProperAlignInChars - Return the ABI-specified alignment of a type, in

/// characters. Except on AIX, return the preferred type alignment instead when

/// under power alignment rules.

CharUnits ASTContext::getTypeProperAlignInChars(QualType T) const {

  if (Target->defaultsToAIXPowerAlignment())

    return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr()));

 

  return getTypeAlignInChars(T);

}

 

Take the calculation of cookie size for array new operator for example, we need:

 

CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {

  // The array cookie is a size_t; pad that up to the element alignment.

  // The cookie is actually right-justified in that space.

  return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes),

-                           CGM.getContext().getTypeAlignInChars(elementType));

+                          CGM.getContext().getTypeProperAlignInChars(elementType));

}

 

Cons:

The migration risk is high. We cannot guarantee in the future the developers would know this is the interface they should use as always for any common path code. So it seems this is not a viable method.

 

2. Add a flag

Adding a flag like the following can help us:

 

e.g.1 – getTypeAlignInChars

/// If ` NeedsABIAlignment ` is false, this function will smartly return preferred alignment

/// or ABI alignment depends on if the target defaults to AIX power alignment or not;

/// Set ` NeedsABIAlignment ` as true if an ABI alignment is needed no matter what target is.

CharUnits ASTContext::getTypeAlignInChars(QualType T, bool NeedsABIAlignment = false) const {
   if (NeedsABIAlignment)
     return toCharUnitsFromBits(getTypeAlign(T));
   if (Target->defaultsToAIXPowerAlignment())
     return toCharUnitsFromBits(getPreferredTypeAlign(T.getTypePtr())); 

 

   return toCharUnitsFromBits(getTypeAlign(T));
}

 

Take cookie size for array new operator calculation for example again, we don’t need to make any change anymore.

 

 

e.g.2 - getTypeInfoImpl

TypeInfo ASTContext::getTypeInfoImpl(const Type *T, bool NeedsABIAlignment = false) const {

...

  switch (T->getTypeClass()) {

...

    case Type::Record:

        const auto *RT = cast<RecordType>(TT);

        const RecordDecl *RD = RT->getDecl();

        const ASTRecordLayout &Layout = getASTRecordLayout(RD);

        Width = toBits(Layout.getSize());

+     if (NeedsABIAlignment)

+       Align = toBits(Layout.getAlignment());

+     else if (Target->defaultsToAIXPowerAlignment())

+       Align = toBits(Layout.getPreferredAlignment());

+     else

          Align = toBits(Layout.getAlignment());

        AlignIsRequired = RD->hasAttr<AlignedAttr>();

        break;

  }

...

}

 

An usage example on the call site:

<Clang/ lib/AST/RecordLayoutBuilder.cpp>

  auto setDeclInfo = [&](bool IsIncompleteArrayType) {

-   TypeInfo TI = Context.getTypeInfo(D->getType());

+  TypeInfo TI = Context.getTypeInfo(D->getType(), true/* NeedsABIAlignment */);

    FieldAlign = Context.toCharUnitsFromBits(TI.Align);

    // Flexible array members don't have any size, but they have to be

    // aligned appropriately for their element type.

    EffectiveFieldSize = FieldSize =

        IsIncompleteArrayType ? CharUnits::Zero()

                              : Context.toCharUnitsFromBits(TI.Width);

    AlignIsRequired = TI.AlignIsRequired;

  };

 

 

Pros:

1) By adding a flag like above, we can minimize the changes needed to make. The scope of changes will be shortened to only a few spots where an ABI alignment is necessary even when AIX special alignment is set.

2) Letting people consciously pass `true`  in if needed is another benefit. Then targets like AIX don’t need to worry about things going wrong accidentally in the future.

 

 

cons:

Those four functions I mentioned above won’t return ABI-specified alignment values all the time anymore.

 

 

I would like to see how people think about our proposal. Any concerns? Or any other ideas to suggest?

 

Please let me know if there are any questions about our current proposal and design. Your feedback is appreciated.

 

Regards,

 

Xiangling Liao

 

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.

 

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
Yeah, I agree that the alignment of a pointer to double on AIX should be 4 under 32-bit.

I should've made it clearer.  By "useless" I mean, we can always trust "PreferredAlignment" but not "ABI alignment" to give us the actual alignment value on AIX of a type "T".

More specifically, regarding aggregate, double, long double type, "PreferredAlignment" gives us the actual alignment of these types. For other types, on AIX, "PreferredAlignment" also gives us the actual alignment of these types by containing the ABI alignment value underneath. So that means, for the example you mentioned previously, even if the alignment of the pointer under 32-bit would take "PreferredAlignment", it is actually using "ABI alignment" which is 4.

That's why we proposed to use "PreferredAlignment" for AIX almost everywhere instead and use "flag" to force using ABI alignment when necessary.

And I understand that we can investigate each spot where an ABI alignment is used, and may replace it with "PreferredAlignment" if needed, but it seems pretty time-consuming and I am not confident to know each usage of those four functions well and make the right decision.

Regards,
Xiangling

On Tue, Aug 18, 2020 at 12:21 PM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

On Tue, Aug 18, 2020, 3:07 PM Xiangling Liao <[hidden email]> wrote:
Yeah, I agree that the alignment of a pointer to double on AIX should be 4 under 32-bit.

I should've made it clearer.  By "useless" I mean, we can always trust "PreferredAlignment" but not "ABI alignment" to give us the actual alignment value on AIX of a type "T".

More specifically, regarding aggregate, double, long double type, "PreferredAlignment" gives us the actual alignment of these types. For other types, on AIX, "PreferredAlignment" also gives us the actual alignment of these types by containing the ABI alignment value underneath. So that means, for the example you mentioned previously, even if the alignment of the pointer under 32-bit would take "PreferredAlignment", it is actually using "ABI alignment" which is 4.

That's why we proposed to use "PreferredAlignment" for AIX almost everywhere instead and use "flag" to force using ABI alignment when necessary.

And I understand that we can investigate each spot where an ABI alignment is used, and may replace it with "PreferredAlignment" if needed, but it seems pretty time-consuming and I am not confident to know each usage of those four functions well and make the right decision.

Regards,
Xiangling

On Tue, Aug 18, 2020 at 12:21 PM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

Thank you for your explanation, I think I see what you mean now. But I want to double confirm that my understanding is correct.

 

Regarding the previous two concepts you listed:

 

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

 

what can I know for sure about the alignment of that pointer” I assume you mean “the alignment of the pointee”. So this means we should always use ABI alignment for the pointee, because it’s an unknown object for the compiler right?

 

Besides that, any other scenarios you are aware of that we should always use ABI alignment?

 

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

 

Does this mean when we “allocate a brand new complete object of type T”, we will prioritize/take “PreferredAlignment”?

 

 

Regarding X86-32, can you show me an example of how X86-32 makes the choice between PreferredAlignment and ABI alignment for “double” type?

 

Thank you,

Xiangling

 

 


On Wed, Aug 19, 2020 at 3:16 PM James Y Knight <[hidden email]> wrote:
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

On Tue, Aug 18, 2020, 3:07 PM Xiangling Liao <[hidden email]> wrote:
Yeah, I agree that the alignment of a pointer to double on AIX should be 4 under 32-bit.

I should've made it clearer.  By "useless" I mean, we can always trust "PreferredAlignment" but not "ABI alignment" to give us the actual alignment value on AIX of a type "T".

More specifically, regarding aggregate, double, long double type, "PreferredAlignment" gives us the actual alignment of these types. For other types, on AIX, "PreferredAlignment" also gives us the actual alignment of these types by containing the ABI alignment value underneath. So that means, for the example you mentioned previously, even if the alignment of the pointer under 32-bit would take "PreferredAlignment", it is actually using "ABI alignment" which is 4.

That's why we proposed to use "PreferredAlignment" for AIX almost everywhere instead and use "flag" to force using ABI alignment when necessary.

And I understand that we can investigate each spot where an ABI alignment is used, and may replace it with "PreferredAlignment" if needed, but it seems pretty time-consuming and I am not confident to know each usage of those four functions well and make the right decision.

Regards,
Xiangling

On Tue, Aug 18, 2020 at 12:21 PM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
In reply to this post by Hubert Tong via cfe-dev
On Wed, 19 Aug 2020 at 12:16, James Y Knight via cfe-dev <[hidden email]> wrote:
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

It seems to me that the term "ABI alignment" is actively confusing matters here -- both alignment values are part of the ABI in the AIX case. Perhaps "minimum alignment" would be a better term for the alignment that all objects of the type are guaranteed to have?

On Tue, Aug 18, 2020, 3:07 PM Xiangling Liao <[hidden email]> wrote:
Yeah, I agree that the alignment of a pointer to double on AIX should be 4 under 32-bit.

I should've made it clearer.  By "useless" I mean, we can always trust "PreferredAlignment" but not "ABI alignment" to give us the actual alignment value on AIX of a type "T".

More specifically, regarding aggregate, double, long double type, "PreferredAlignment" gives us the actual alignment of these types. For other types, on AIX, "PreferredAlignment" also gives us the actual alignment of these types by containing the ABI alignment value underneath. So that means, for the example you mentioned previously, even if the alignment of the pointer under 32-bit would take "PreferredAlignment", it is actually using "ABI alignment" which is 4.

That's why we proposed to use "PreferredAlignment" for AIX almost everywhere instead and use "flag" to force using ABI alignment when necessary.

And I understand that we can investigate each spot where an ABI alignment is used, and may replace it with "PreferredAlignment" if needed, but it seems pretty time-consuming and I am not confident to know each usage of those four functions well and make the right decision.

Regards,
Xiangling

On Tue, Aug 18, 2020 at 12:21 PM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
On Wed, Aug 19, 2020 at 5:57 PM Richard Smith <[hidden email]> wrote:
On Wed, 19 Aug 2020 at 12:16, James Y Knight via cfe-dev <[hidden email]> wrote:
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

It seems to me that the term "ABI alignment" is actively confusing matters here -- both alignment values are part of the ABI in the AIX case. Perhaps "minimum alignment" would be a better term for the alignment that all objects of the type are guaranteed to have?

I agree that "ABI alignment" is a poor name. I like calling it "guaranteed type alignment".

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
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.
  • 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.
  • 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.
  • 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.
  • alignof(T) / __alignof(T) must return the "ABI" and "preferred" alignments of T, respectively.
And here are Xiangling’s responses/new questions reproduced again, to get back to the specifics:

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

 

what can I know for sure about the alignment of that pointer” I assume you mean “the alignment of the pointee”. So this means we should always use ABI alignment for the pointee, because it’s an unknown object for the compiler right? 

 

Besides that, any other scenarios you are aware of that we should always use ABI alignment?

 

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

 

Does this mean when we “allocate a brand new complete object of type T”, we will prioritize/take “PreferredAlignment”?

 

 

Regarding X86-32, can you show me an example of how X86-32 makes the choice between PreferredAlignment and ABI alignment for “double” type? 

 

Thank you,
Xiangling



On Aug 19, 2020, at 6:07 PM, James Y Knight via cfe-dev <[hidden email]> wrote:

On Wed, Aug 19, 2020 at 5:57 PM Richard Smith <[hidden email]> wrote:
On Wed, 19 Aug 2020 at 12:16, James Y Knight via cfe-dev <[hidden email]> wrote:
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

It seems to me that the term "ABI alignment" is actively confusing matters here -- both alignment values are part of the ABI in the AIX case. Perhaps "minimum alignment" would be a better term for the alignment that all objects of the type are guaranteed to have?

I agree that "ABI alignment" is a poor name. I like calling it "guaranteed type alignment".
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
In reply to this post by Hubert Tong via cfe-dev


On Wed, Aug 19, 2020 at 5:21 PM Xiangling Liao <[hidden email]> wrote:

Thank you for your explanation, I think I see what you mean now. But I want to double confirm that my understanding is correct.

 

Regarding the previous two concepts you listed:

 

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

 

what can I know for sure about the alignment of that pointer” I assume you mean “the alignment of the pointee”. So this means we should always use ABI alignment for the pointee, because it’s an unknown object for the compiler right?

 

Besides that, any other scenarios you are aware of that we should always use ABI alignment?


Yes, exactly right. But this, I suspect, covers the majority of the callers asking about type alignment within the compiler.

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

 

Does this mean when we “allocate a brand new complete object of type T”, we will prioritize/take “PreferredAlignment”?


Correct. Except, today, we only use the preferred alignment when allocating memory backing a variable on the stack or in global/thread local memory. See the code in ASTContext::getDeclAlign.

We do not currently use preferred alignment for dynamic memory allocation like "new double", as you've noticed. That may well be simply because on all previously supported ABIs, the difference isn't even observable for dynamic allocation, because the only types which had different preferred alignments were 'double' and 'long long'. These got a preferred alignment of 8 vs the abi alignment of 4. But, since the minimum alignment from 'operator new' is already 8 or 16, and no size-cookie is used for arrays of these types (since they don't have destructors), it is actually irrelevant whether we've asked for 4 or 8 byte alignment in this context.

It's entirely possible that there's additional locations in the code beyond that where the preferred type alignment should or could be used. But that'll need to be decided on a case by case basis looking at what each caller to getTypeAlign is using it for.

Regarding X86-32, can you show me an example of how X86-32 makes the choice between PreferredAlignment and ABI alignment for “double” type?


See above.

 

Thank you,

Xiangling

 

 


On Wed, Aug 19, 2020 at 3:16 PM James Y Knight <[hidden email]> wrote:
I wasn't talking about the alignment of a pointer, but rather the alignment of a value of type 'double', which has a preferred alignment of 8.

Not all double values in memory are 8 byte aligned -- some are placed only at 4 byte aligned offsets. Therefore, the compiler can only assume an alignment of 4 for an unknown object of type 'double' -- this is the abi alignment.

On Tue, Aug 18, 2020, 3:07 PM Xiangling Liao <[hidden email]> wrote:
Yeah, I agree that the alignment of a pointer to double on AIX should be 4 under 32-bit.

I should've made it clearer.  By "useless" I mean, we can always trust "PreferredAlignment" but not "ABI alignment" to give us the actual alignment value on AIX of a type "T".

More specifically, regarding aggregate, double, long double type, "PreferredAlignment" gives us the actual alignment of these types. For other types, on AIX, "PreferredAlignment" also gives us the actual alignment of these types by containing the ABI alignment value underneath. So that means, for the example you mentioned previously, even if the alignment of the pointer under 32-bit would take "PreferredAlignment", it is actually using "ABI alignment" which is 4.

That's why we proposed to use "PreferredAlignment" for AIX almost everywhere instead and use "flag" to force using ABI alignment when necessary.

And I understand that we can investigate each spot where an ABI alignment is used, and may replace it with "PreferredAlignment" if needed, but it seems pretty time-consuming and I am not confident to know each usage of those four functions well and make the right decision.

Regards,
Xiangling

On Tue, Aug 18, 2020 at 12:21 PM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020 at 11:01 AM Xiangling Liao <[hidden email]> wrote:

It looks to me as if at least examples 1, 2, and 4 are places that should not be changed to use the "AIX preferred" alignment, because they are inquiring about the guaranteed alignment of an existing pointer, which may well not have been placed at the preferred alignment. I haven't dug into the code beyond your snippet so I'm not sure about examples 3 and 5.

 

To be honest, I am not familiar with every snippet where functions like “getTypeAlignInChars” is used. So I just list some locations that call “getTypeAlignInChars”. But I did mean that we probably should replace them with “PreferredAlignment” for AIX.

 

1. In AIX rules, not only an aggregate can now have a different preferred alignment from guaranteed alignment, but also double, long double.

 

We see the semantic of “PreferredAlignment” on AIX represents a “T”’s actual alignment. In other words, ABI alignment on AIX is kinda useless except for being used to let “alignof(T)” return a correct value.


I feel like there's a fundamental misunderstanding here -- the ABI alignment is not at all useless. Please see my previous email about the two different concepts of alignment.

For example, the AIX preferred alignment of 'double' is 8, and the guaranteed ("ABI") alignment is 4. If you compile the following function, the load/store instructions must be emitted with "align 4" and not "align 8" on them, because that's all that you know about a pointer to double.
  void foo(double* out, double* in) { *out = *in * 2; }

2. For the example1, you mentioned the “the guaranteed alignment of an existing pointer may well not have been placed at the preferred alignment”. But as I know, what function “getPreferredTypeAlign” does is to get the ABI/guaranteed alignment of a “T” first by invoking “getTypeInfo”, and then minor adjust some values. So we seems don’t need to worry about we cannot get a pointer’s ABI alignment, and many other cases as well, if that’s the correct one for AIX.

 

Besides, I am not sure if I understand the code snippet right in example1.

 

  // If that failed, return the type's alignment.

  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());

}

 

A pointer’s pointeeType can be anything, which may be an aggregate,  double, or long doble etc. For those types, on AIX, we do need to get the “PreferredAlignment”?

 

3. So far, I didn’t investigate every usage of those four functions:

1) getTypeAlignInChars [invokes getTypeAlign]

2) getTypeAlign <=> getTypeInfo(T).Align

3) getTypeInfo [ invokes ‘getTypeInfoImpl’]

4) getTypeInfoInChars

 

Because I am not sure if we really want to spend a lot of time on digging each crack. An initial scan of them shows a large amount of them used in Clang. How do you think about this?

 

 

And most importantly, besides of “adding a flag” way to handle speical alignment on AIX, I am wondering in which way we can handle it better?

 

 

Regards,
Xiangling

 

 

 

 

 

 



On Tue, Aug 18, 2020 at 8:48 AM James Y Knight <[hidden email]> wrote:


On Tue, Aug 18, 2020, 12:54 AM David Rector <[hidden email]> wrote:
I would have to think that, whatever the documentation for  e.g. getTypeAlignInChars(T), most users expect it to return T’s actual alignment for their target, whether it was determined from the ABI, or the AIX alignment scheme, or whatever.

There really are two concepts at play here.

1. Given a pointer to some object of type T or a field of type T inside another object, what can I know for sure about the alignment of that pointer? (How many of the low bits are absolutely guaranteed to be 0, assuming the program doesn't involve Undefined Behavior?)

2. If I want to allocate a brand new complete object of type T, at what alignment should I use to place it? This must be at least the alignment from 1. But beyond that, it could differ by circumstance, e.g. stack, global, and function parameter allocations could make different choices. In some cases, increasing the alignment of an allocation above the required minimum may just be an optimization, but in other cases it has an ABI impact.

AIX is not the first platform where these alignments differ -- the type 'double' on x86-32 being the other notable example. But, the AIX rules trigger differences in more circumstances than we've had before, and thus we now need to potentially make a choice in other parts of the code. Importantly: in AIX rules, an aggregate can now have a different preferred alignment from guaranteed alignment, too.

The first case brought up where this surely matters, is 'new T[100]' where T has a destructor. This thread is exploring whether there are other such cases that we might need to change, too. I suspect that there are not many, but that remains to be determined.




In fact, maybe we can go further: I would think that any valid use of type alignment which explicitly ignores AIX or other target-specific alignment schemes are probably just implementation details used only in the calculation of some composed type’s alignment under that scheme.  In other words I would assume every function call in which AIX preferred alignment needed to be ignored is in the some layout-building implementation — is that right?

E.g. the lib/AST/RecordLayoutBuilder.cpp example you cite below fits this description — in LayoutField(FieldDecl *D, …) you propose to change the call to fetch the ABI/non-AIX type info via 
getTypeInfo(D->getType(), true/* NeedsABIAlignment */);
but only so that you can later tweak that info whenever DefaultsToAIXPowerAlignment==true

If all the changes you would need to make are indeed similar to this, these expanded usages are really only implementation details needed to build type layouts, and thus the goal should simply be to sufficiently hide these details from common programmers who don’t need to build type layouts, only access them.

I think your original option #2 ("add a flag"), i.e. adding new defaulted parameters to a few functions, seems to be a reasonable way to hide these new details, so long as the new parameters are well named and documented.  It also seems sufficiently general to be useful for implementing other special default alignment schemes in the future.

Dave


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev
In reply to this post by Hubert Tong via cfe-dev


On Wed, Aug 19, 2020 at 8:53 PM David Rector <[hidden email]> 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.


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev


On Aug 20, 2020, at 9:26 AM, James Y Knight <[hidden email]> wrote:



On Wed, Aug 19, 2020 at 8:53 PM David Rector <[hidden email]> 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



_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Use preferred alignment instead of ABI alignment for complete object when applicable

Hubert Tong via cfe-dev

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 <[hidden email]> wrote:


On Aug 20, 2020, at 9:26 AM, James Y Knight <[hidden email]> wrote:



On Wed, Aug 19, 2020 at 8:53 PM David Rector <[hidden email]> 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



_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
12