about element size/alignment in an array

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

about element size/alignment in an array

shirley breuer via cfe-dev
Hi, there.

I met a problem about element size/alignment in an array. I defined the following vector type.
-------------------------------------------------------------------------------------------------------------------------
typedef int __attribute__((__vector_size__(64), aligned(128))) v16i32;
struct container {
    v16i32 arr[10];
    v16i32 val;
} stu;
-------------------------------------------------------------------------------------------------------------------------
Its size is 512bits. And alignment is 1024bits.
I also defined the datalayout in clang and llvm, "v512:1024". I need vector of 512bits to be aligned to 1024bits no matter whether it is in an array or not.

but I saw the code as below in clang/lib/AST/ASTContext.cpp. line 1749
--------------------------------------------------------------------------------------------------------------------------
/// getConstantArrayInfoInChars - Performing the computation in CharUnits
/// instead of in bits prevents overflowing the uint64_t for some large arrays.
std::pair<CharUnits, CharUnits>
static getConstantArrayInfoInChars(const ASTContext &Context,
                                   const ConstantArrayType *CAT) {
  std::pair<CharUnits, CharUnits> EltInfo =
      Context.getTypeInfoInChars(CAT->getElementType());
  uint64_t Size = CAT->getSize().getZExtValue();
  assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <=
              (uint64_t)(-1)/Size) &&
         "Overflow in array type char size evaluation");
  uint64_t Width = EltInfo.first.getQuantity() * Size;                  //here
  unsigned Align = EltInfo.second.getQuantity();
  if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
      Context.getTargetInfo().getPointerWidth(0) == 64)
    Width = llvm::alignTo(Width, Align);
  return std::make_pair(CharUnits::fromQuantity(Width),
                        CharUnits::fromQuantity(Align));
}
--------------------------------------------------------------------------------------------------------------------------
when caculating the size of an array, the alignment of element is not considered. Thus the width of the array "arr" in struct container is 512x10bits, not 1024x10bits.
And the offset of "val" in struct container is 512x10bits. That's 640bytes.
but it is not the way in which size of "arr" is caculated in CGRecordLowering::clipTailPadding(), line 586 of clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
--------------------------------------------------------------------------------------------------------------------------
void CGRecordLowering::clipTailPadding() {
  std::vector<MemberInfo>::iterator Prior = Members.begin();
  CharUnits Tail = getSize(Prior->Data);   //here
  for (std::vector<MemberInfo>::iterator Member = Prior + 1,
                                         MemberEnd = Members.end();
       Member != MemberEnd; ++Member) {
    // Only members with data and the scissor can cut into tail padding.
    if (!Member->Data && Member->Kind != MemberInfo::Scissor)
      continue;
    if (Member->Offset < Tail) {               // and here
      assert(Prior->Kind == MemberInfo::Field &&
             "Only storage fields have tail padding!");
      if (!Prior->FD || Prior->FD->isBitField())
        Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
            cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
      else {
        assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() &&
               "should not have reused this field's tail padding");     // doesn't meet this assert
        Prior->Data = getByteArrayType(
            Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).first);
      }
    }
    if (Member->Data)
      Prior = Member;
    Tail = Prior->Offset + getSize(Prior->Data);
  }
}
--------------------------------------------------------------------------------------------------------------------------
the "getSize(Prior->Data)" function will consider the alignment of element. When "Prior" points to the first field "arr" of struct container, "Tail" is 1024x10/8 = 1280 bytes. That's the size of type [10 x <16 x i32>] considering alignment.
At the first iteration of for loop, "Member" points to the second field "val" of struct container. "Member->Offset" is 640bytes.
"if (Member->Offset < Tail)" is true, and the execution goes in. And later "else" branch is executed. 
The "assert" in else clause will fail, and clang will crash.

I think when caculating the size of an array, the alignment of element should also be considered. But it is not the case in code.
I am not sure whether it is a bug in clang or there is something I don't know.
Could anyone help me? Thanks in advance!


Best Regards,
Jerry





 


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