brintos

brintos / llvm-project-archived public Read only

0
0
Text · 40.1 KiB · 87f2340 Raw
1020 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This contains code to compute the layout of a record.10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenBuilder.h"14#include "CIRGenModule.h"15#include "CIRGenTypes.h"16 17#include "clang/AST/ASTContext.h"18#include "clang/AST/Decl.h"19#include "clang/AST/DeclCXX.h"20#include "clang/AST/RecordLayout.h"21#include "clang/CIR/Dialect/IR/CIRAttrs.h"22#include "clang/CIR/Dialect/IR/CIRDataLayout.h"23#include "clang/CIR/MissingFeatures.h"24#include "llvm/Support/Casting.h"25 26#include <memory>27 28using namespace llvm;29using namespace clang;30using namespace clang::CIRGen;31 32namespace {33/// The CIRRecordLowering is responsible for lowering an ASTRecordLayout to an34/// mlir::Type. Some of the lowering is straightforward, some is not.35// TODO: Detail some of the complexities and weirdnesses?36// (See CGRecordLayoutBuilder.cpp)37struct CIRRecordLowering final {38 39  // MemberInfo is a helper structure that contains information about a record40  // member. In addition to the standard member types, there exists a sentinel41  // member type that ensures correct rounding.42  struct MemberInfo final {43    CharUnits offset;44    enum class InfoKind { VFPtr, Field, Base, VBase } kind;45    mlir::Type data;46    union {47      const FieldDecl *fieldDecl;48      const CXXRecordDecl *cxxRecordDecl;49    };50    MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,51               const FieldDecl *fieldDecl = nullptr)52        : offset{offset}, kind{kind}, data{data}, fieldDecl{fieldDecl} {}53    MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,54               const CXXRecordDecl *rd)55        : offset{offset}, kind{kind}, data{data}, cxxRecordDecl{rd} {}56    // MemberInfos are sorted so we define a < operator.57    bool operator<(const MemberInfo &other) const {58      return offset < other.offset;59    }60  };61  // The constructor.62  CIRRecordLowering(CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,63                    bool packed);64 65  /// Constructs a MemberInfo instance from an offset and mlir::Type.66  MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data) {67    return MemberInfo(offset, MemberInfo::InfoKind::Field, data);68  }69 70  // Layout routines.71  void setBitFieldInfo(const FieldDecl *fd, CharUnits startOffset,72                       mlir::Type storageType);73 74  void lower(bool NonVirtualBaseType);75  void lowerUnion();76 77  /// Determines if we need a packed llvm struct.78  void determinePacked(bool nvBaseType);79  /// Inserts padding everywhere it's needed.80  void insertPadding();81 82  void computeVolatileBitfields();83  void accumulateBases();84  void accumulateVPtrs();85  void accumulateVBases();86  void accumulateFields();87  RecordDecl::field_iterator88  accumulateBitFields(RecordDecl::field_iterator field,89                      RecordDecl::field_iterator fieldEnd);90 91  mlir::Type getVFPtrType();92 93  bool isAAPCS() const {94    return astContext.getTargetInfo().getABI().starts_with("aapcs");95  }96 97  /// Helper function to check if the target machine is BigEndian.98  bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }99 100  // The Itanium base layout rule allows virtual bases to overlap101  // other bases, which complicates layout in specific ways.102  //103  // Note specifically that the ms_struct attribute doesn't change this.104  bool isOverlappingVBaseABI() {105    return !astContext.getTargetInfo().getCXXABI().isMicrosoft();106  }107  // Recursively searches all of the bases to find out if a vbase is108  // not the primary vbase of some base class.109  bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);110 111  /// The Microsoft bitfield layout rule allocates discrete storage112  /// units of the field's formal type and only combines adjacent113  /// fields of the same formal type.  We want to emit a layout with114  /// these discrete storage units instead of combining them into a115  /// continuous run.116  bool isDiscreteBitFieldABI() {117    return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||118           recordDecl->isMsStruct(astContext);119  }120 121  CharUnits bitsToCharUnits(uint64_t bitOffset) {122    return astContext.toCharUnitsFromBits(bitOffset);123  }124 125  void calculateZeroInit();126 127  CharUnits getSize(mlir::Type Ty) {128    return CharUnits::fromQuantity(dataLayout.layout.getTypeSize(Ty));129  }130  CharUnits getSizeInBits(mlir::Type ty) {131    return CharUnits::fromQuantity(dataLayout.layout.getTypeSizeInBits(ty));132  }133  CharUnits getAlignment(mlir::Type Ty) {134    return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty));135  }136 137  bool isZeroInitializable(const FieldDecl *fd) {138    return cirGenTypes.isZeroInitializable(fd->getType());139  }140  bool isZeroInitializable(const RecordDecl *rd) {141    return cirGenTypes.isZeroInitializable(rd);142  }143 144  /// Wraps cir::IntType with some implicit arguments.145  mlir::Type getUIntNType(uint64_t numBits) {146    unsigned alignedBits = llvm::PowerOf2Ceil(numBits);147    alignedBits = std::max(8u, alignedBits);148    return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,149                             /*isSigned=*/false);150  }151 152  mlir::Type getCharType() {153    return cir::IntType::get(&cirGenTypes.getMLIRContext(),154                             astContext.getCharWidth(),155                             /*isSigned=*/false);156  }157 158  mlir::Type getByteArrayType(CharUnits numberOfChars) {159    assert(!numberOfChars.isZero() && "Empty byte arrays aren't allowed.");160    mlir::Type type = getCharType();161    return numberOfChars == CharUnits::One()162               ? type163               : cir::ArrayType::get(type, numberOfChars.getQuantity());164  }165 166  // Gets the CIR BaseSubobject type from a CXXRecordDecl.167  mlir::Type getStorageType(const CXXRecordDecl *RD) {168    return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();169  }170  // This is different from LLVM traditional codegen because CIRGen uses arrays171  // of bytes instead of arbitrary-sized integers. This is important for packed172  // structures support.173  mlir::Type getBitfieldStorageType(unsigned numBits) {174    unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());175    if (cir::isValidFundamentalIntWidth(alignedBits))176      return builder.getUIntNTy(alignedBits);177 178    mlir::Type type = getCharType();179    return cir::ArrayType::get(type, alignedBits / astContext.getCharWidth());180  }181 182  mlir::Type getStorageType(const FieldDecl *fieldDecl) {183    mlir::Type type = cirGenTypes.convertTypeForMem(fieldDecl->getType());184    if (fieldDecl->isBitField()) {185      cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),186                                         "getStorageType for bitfields");187    }188    return type;189  }190 191  uint64_t getFieldBitOffset(const FieldDecl *fieldDecl) {192    return astRecordLayout.getFieldOffset(fieldDecl->getFieldIndex());193  }194 195  /// Fills out the structures that are ultimately consumed.196  void fillOutputFields();197 198  void appendPaddingBytes(CharUnits size) {199    if (!size.isZero()) {200      fieldTypes.push_back(getByteArrayType(size));201      padded = true;202    }203  }204 205  CIRGenTypes &cirGenTypes;206  CIRGenBuilderTy &builder;207  const ASTContext &astContext;208  const RecordDecl *recordDecl;209  const CXXRecordDecl *cxxRecordDecl;210  const ASTRecordLayout &astRecordLayout;211  // Helpful intermediate data-structures212  std::vector<MemberInfo> members;213  // Output fields, consumed by CIRGenTypes::computeRecordLayout214  llvm::SmallVector<mlir::Type, 16> fieldTypes;215  llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;216  llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;217  llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;218  llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;219  cir::CIRDataLayout dataLayout;220 221  LLVM_PREFERRED_TYPE(bool)222  unsigned zeroInitializable : 1;223  LLVM_PREFERRED_TYPE(bool)224  unsigned zeroInitializableAsBase : 1;225  LLVM_PREFERRED_TYPE(bool)226  unsigned packed : 1;227  LLVM_PREFERRED_TYPE(bool)228  unsigned padded : 1;229 230private:231  CIRRecordLowering(const CIRRecordLowering &) = delete;232  void operator=(const CIRRecordLowering &) = delete;233}; // CIRRecordLowering234} // namespace235 236CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes,237                                     const RecordDecl *recordDecl, bool packed)238    : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},239      astContext{cirGenTypes.getASTContext()}, recordDecl{recordDecl},240      cxxRecordDecl{llvm::dyn_cast<CXXRecordDecl>(recordDecl)},241      astRecordLayout{242          cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)},243      dataLayout{cirGenTypes.getCGModule().getModule()},244      zeroInitializable{true}, zeroInitializableAsBase{true}, packed{packed},245      padded{false} {}246 247void CIRRecordLowering::setBitFieldInfo(const FieldDecl *fd,248                                        CharUnits startOffset,249                                        mlir::Type storageType) {250  CIRGenBitFieldInfo &info = bitFields[fd->getCanonicalDecl()];251  info.isSigned = fd->getType()->isSignedIntegerOrEnumerationType();252  info.offset =253      (unsigned)(getFieldBitOffset(fd) - astContext.toBits(startOffset));254  info.size = fd->getBitWidthValue();255  info.storageSize = getSizeInBits(storageType).getQuantity();256  info.storageOffset = startOffset;257  info.storageType = storageType;258  info.name = fd->getName();259 260  if (info.size > info.storageSize)261    info.size = info.storageSize;262  // Reverse the bit offsets for big endian machines. Since bitfields are laid263  // out as packed bits within an integer-sized unit, we can imagine the bits264  // counting from the most-significant-bit instead of the265  // least-significant-bit.266  if (dataLayout.isBigEndian())267    info.offset = info.storageSize - (info.offset + info.size);268 269  info.volatileStorageSize = 0;270  info.volatileOffset = 0;271  info.volatileStorageOffset = CharUnits::Zero();272}273 274void CIRRecordLowering::lower(bool nonVirtualBaseType) {275  if (recordDecl->isUnion()) {276    lowerUnion();277    computeVolatileBitfields();278    return;279  }280 281  CharUnits size = nonVirtualBaseType ? astRecordLayout.getNonVirtualSize()282                                      : astRecordLayout.getSize();283 284  accumulateFields();285 286  if (cxxRecordDecl) {287    accumulateVPtrs();288    accumulateBases();289    if (members.empty()) {290      appendPaddingBytes(size);291      computeVolatileBitfields();292      return;293    }294    if (!nonVirtualBaseType)295      accumulateVBases();296  }297 298  llvm::stable_sort(members);299  // TODO: Verify bitfield clipping300  assert(!cir::MissingFeatures::checkBitfieldClipping());301 302  members.push_back(makeStorageInfo(size, getUIntNType(8)));303  determinePacked(nonVirtualBaseType);304  insertPadding();305  members.pop_back();306 307  calculateZeroInit();308  fillOutputFields();309  computeVolatileBitfields();310}311 312void CIRRecordLowering::fillOutputFields() {313  for (const MemberInfo &member : members) {314    if (member.data)315      fieldTypes.push_back(member.data);316    if (member.kind == MemberInfo::InfoKind::Field) {317      if (member.fieldDecl)318        fieldIdxMap[member.fieldDecl->getCanonicalDecl()] =319            fieldTypes.size() - 1;320      // A field without storage must be a bitfield.321      if (!member.data) {322        assert(member.fieldDecl &&323               "member.data is a nullptr so member.fieldDecl should not be");324        setBitFieldInfo(member.fieldDecl, member.offset, fieldTypes.back());325      }326    } else if (member.kind == MemberInfo::InfoKind::Base) {327      nonVirtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;328    } else if (member.kind == MemberInfo::InfoKind::VBase) {329      virtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;330    }331  }332}333 334RecordDecl::field_iterator335CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field,336                                       RecordDecl::field_iterator fieldEnd) {337  if (isDiscreteBitFieldABI()) {338    // run stores the first element of the current run of bitfields. fieldEnd is339    // used as a special value to note that we don't have a current run. A340    // bitfield run is a contiguous collection of bitfields that can be stored341    // in the same storage block. Zero-sized bitfields and bitfields that would342    // cross an alignment boundary break a run and start a new one.343    RecordDecl::field_iterator run = fieldEnd;344    // tail is the offset of the first bit off the end of the current run. It's345    // used to determine if the ASTRecordLayout is treating these two bitfields346    // as contiguous. StartBitOffset is offset of the beginning of the Run.347    uint64_t startBitOffset, tail = 0;348    for (; field != fieldEnd && field->isBitField(); ++field) {349      // Zero-width bitfields end runs.350      if (field->isZeroLengthBitField()) {351        run = fieldEnd;352        continue;353      }354      uint64_t bitOffset = getFieldBitOffset(*field);355      mlir::Type type = cirGenTypes.convertTypeForMem(field->getType());356      // If we don't have a run yet, or don't live within the previous run's357      // allocated storage then we allocate some storage and start a new run.358      if (run == fieldEnd || bitOffset >= tail) {359        run = field;360        startBitOffset = bitOffset;361        tail = startBitOffset + dataLayout.getTypeAllocSizeInBits(type);362        // Add the storage member to the record.  This must be added to the363        // record before the bitfield members so that it gets laid out before364        // the bitfields it contains get laid out.365        members.push_back(366            makeStorageInfo(bitsToCharUnits(startBitOffset), type));367      }368      // Bitfields get the offset of their storage but come afterward and remain369      // there after a stable sort.370      members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),371                                   MemberInfo::InfoKind::Field, nullptr,372                                   *field));373    }374    return field;375  }376 377  CharUnits regSize =378      bitsToCharUnits(astContext.getTargetInfo().getRegisterWidth());379  unsigned charBits = astContext.getCharWidth();380 381  // Data about the start of the span we're accumulating to create an access382  // unit from. 'Begin' is the first bitfield of the span. If 'begin' is383  // 'fieldEnd', we've not got a current span. The span starts at the384  // 'beginOffset' character boundary. 'bitSizeSinceBegin' is the size (in bits)385  // of the span -- this might include padding when we've advanced to a386  // subsequent bitfield run.387  RecordDecl::field_iterator begin = fieldEnd;388  CharUnits beginOffset;389  uint64_t bitSizeSinceBegin;390 391  // The (non-inclusive) end of the largest acceptable access unit we've found392  // since 'begin'. If this is 'begin', we're gathering the initial set of393  // bitfields of a new span. 'bestEndOffset' is the end of that acceptable394  // access unit -- it might extend beyond the last character of the bitfield395  // run, using available padding characters.396  RecordDecl::field_iterator bestEnd = begin;397  CharUnits bestEndOffset;398  bool bestClipped; // Whether the representation must be in a byte array.399 400  for (;;) {401    // atAlignedBoundary is true if 'field' is the (potential) start of a new402    // span (or the end of the bitfields). When true, limitOffset is the403    // character offset of that span and barrier indicates whether the new404    // span cannot be merged into the current one.405    bool atAlignedBoundary = false;406    bool barrier = false; // a barrier can be a zero Bit Width or non bit member407    if (field != fieldEnd && field->isBitField()) {408      uint64_t bitOffset = getFieldBitOffset(*field);409      if (begin == fieldEnd) {410        // Beginning a new span.411        begin = field;412        bestEnd = begin;413 414        assert((bitOffset % charBits) == 0 && "Not at start of char");415        beginOffset = bitsToCharUnits(bitOffset);416        bitSizeSinceBegin = 0;417      } else if ((bitOffset % charBits) != 0) {418        // Bitfield occupies the same character as previous bitfield, it must be419        // part of the same span. This can include zero-length bitfields, should420        // the target not align them to character boundaries. Such non-alignment421        // is at variance with the standards, which require zero-length422        // bitfields be a barrier between access units. But of course we can't423        // achieve that in the middle of a character.424        assert(bitOffset ==425                   astContext.toBits(beginOffset) + bitSizeSinceBegin &&426               "Concatenating non-contiguous bitfields");427      } else {428        // Bitfield potentially begins a new span. This includes zero-length429        // bitfields on non-aligning targets that lie at character boundaries430        // (those are barriers to merging).431        if (field->isZeroLengthBitField())432          barrier = true;433        atAlignedBoundary = true;434      }435    } else {436      // We've reached the end of the bitfield run. Either we're done, or this437      // is a barrier for the current span.438      if (begin == fieldEnd)439        break;440 441      barrier = true;442      atAlignedBoundary = true;443    }444 445    // 'installBest' indicates whether we should create an access unit for the446    // current best span: fields ['begin', 'bestEnd') occupying characters447    // ['beginOffset', 'bestEndOffset').448    bool installBest = false;449    if (atAlignedBoundary) {450      // 'field' is the start of a new span or the end of the bitfields. The451      // just-seen span now extends to 'bitSizeSinceBegin'.452 453      // Determine if we can accumulate that just-seen span into the current454      // accumulation.455      CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);456      if (bestEnd == begin) {457        // This is the initial run at the start of a new span. By definition,458        // this is the best seen so far.459        bestEnd = field;460        bestEndOffset = beginOffset + accessSize;461        // Assume clipped until proven not below.462        bestClipped = true;463        if (!bitSizeSinceBegin)464          // A zero-sized initial span -- this will install nothing and reset465          // for another.466          installBest = true;467      } else if (accessSize > regSize) {468        // Accumulating the just-seen span would create a multi-register access469        // unit, which would increase register pressure.470        installBest = true;471      }472 473      if (!installBest) {474        // Determine if accumulating the just-seen span will create an expensive475        // access unit or not.476        mlir::Type type = getUIntNType(astContext.toBits(accessSize));477        if (!astContext.getTargetInfo().hasCheapUnalignedBitFieldAccess())478          cirGenTypes.getCGModule().errorNYI(479              field->getSourceRange(), "NYI CheapUnalignedBitFieldAccess");480 481        if (!installBest) {482          // Find the next used storage offset to determine what the limit of483          // the current span is. That's either the offset of the next field484          // with storage (which might be field itself) or the end of the485          // non-reusable tail padding.486          CharUnits limitOffset;487          for (auto probe = field; probe != fieldEnd; ++probe)488            if (!isEmptyFieldForLayout(astContext, *probe)) {489              // A member with storage sets the limit.490              assert((getFieldBitOffset(*probe) % charBits) == 0 &&491                     "Next storage is not byte-aligned");492              limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));493              goto FoundLimit;494            }495          limitOffset = cxxRecordDecl ? astRecordLayout.getNonVirtualSize()496                                      : astRecordLayout.getDataSize();497 498        FoundLimit:499          CharUnits typeSize = getSize(type);500          if (beginOffset + typeSize <= limitOffset) {501            // There is space before limitOffset to create a naturally-sized502            // access unit.503            bestEndOffset = beginOffset + typeSize;504            bestEnd = field;505            bestClipped = false;506          }507          if (barrier) {508            // The next field is a barrier that we cannot merge across.509            installBest = true;510          } else if (cirGenTypes.getCGModule()511                         .getCodeGenOpts()512                         .FineGrainedBitfieldAccesses) {513            installBest = true;514          } else {515            // Otherwise, we're not installing. Update the bit size516            // of the current span to go all the way to limitOffset, which is517            // the (aligned) offset of next bitfield to consider.518            bitSizeSinceBegin = astContext.toBits(limitOffset - beginOffset);519          }520        }521      }522    }523 524    if (installBest) {525      assert((field == fieldEnd || !field->isBitField() ||526              (getFieldBitOffset(*field) % charBits) == 0) &&527             "Installing but not at an aligned bitfield or limit");528      CharUnits accessSize = bestEndOffset - beginOffset;529      if (!accessSize.isZero()) {530        // Add the storage member for the access unit to the record. The531        // bitfields get the offset of their storage but come afterward and532        // remain there after a stable sort.533        mlir::Type type;534        if (bestClipped) {535          assert(getSize(getUIntNType(astContext.toBits(accessSize))) >536                     accessSize &&537                 "Clipped access need not be clipped");538          type = getByteArrayType(accessSize);539        } else {540          type = getUIntNType(astContext.toBits(accessSize));541          assert(getSize(type) == accessSize &&542                 "Unclipped access must be clipped");543        }544        members.push_back(makeStorageInfo(beginOffset, type));545        for (; begin != bestEnd; ++begin)546          if (!begin->isZeroLengthBitField())547            members.push_back(MemberInfo(548                beginOffset, MemberInfo::InfoKind::Field, nullptr, *begin));549      }550      // Reset to start a new span.551      field = bestEnd;552      begin = fieldEnd;553    } else {554      assert(field != fieldEnd && field->isBitField() &&555             "Accumulating past end of bitfields");556      assert(!barrier && "Accumulating across barrier");557      // Accumulate this bitfield into the current (potential) span.558      bitSizeSinceBegin += field->getBitWidthValue();559      ++field;560    }561  }562 563  return field;564}565 566void CIRRecordLowering::accumulateFields() {567  for (RecordDecl::field_iterator field = recordDecl->field_begin(),568                                  fieldEnd = recordDecl->field_end();569       field != fieldEnd;) {570    if (field->isBitField()) {571      field = accumulateBitFields(field, fieldEnd);572      assert((field == fieldEnd || !field->isBitField()) &&573             "Failed to accumulate all the bitfields");574    } else if (!field->isZeroSize(astContext)) {575      members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)),576                                   MemberInfo::InfoKind::Field,577                                   getStorageType(*field), *field));578      ++field;579    } else {580      // TODO(cir): do we want to do anything special about zero size members?581      assert(!cir::MissingFeatures::zeroSizeRecordMembers());582      ++field;583    }584  }585}586 587void CIRRecordLowering::calculateZeroInit() {588  for (const MemberInfo &member : members) {589    if (member.kind == MemberInfo::InfoKind::Field) {590      if (!member.fieldDecl || isZeroInitializable(member.fieldDecl))591        continue;592      zeroInitializable = zeroInitializableAsBase = false;593      return;594    } else if (member.kind == MemberInfo::InfoKind::Base ||595               member.kind == MemberInfo::InfoKind::VBase) {596      if (isZeroInitializable(member.cxxRecordDecl))597        continue;598      zeroInitializable = false;599      if (member.kind == MemberInfo::InfoKind::Base)600        zeroInitializableAsBase = false;601    }602  }603}604 605void CIRRecordLowering::determinePacked(bool nvBaseType) {606  if (packed)607    return;608  CharUnits alignment = CharUnits::One();609  CharUnits nvAlignment = CharUnits::One();610  CharUnits nvSize = !nvBaseType && cxxRecordDecl611                         ? astRecordLayout.getNonVirtualSize()612                         : CharUnits::Zero();613 614  for (const MemberInfo &member : members) {615    if (!member.data)616      continue;617    // If any member falls at an offset that it not a multiple of its alignment,618    // then the entire record must be packed.619    if (!member.offset.isMultipleOf(getAlignment(member.data)))620      packed = true;621    if (member.offset < nvSize)622      nvAlignment = std::max(nvAlignment, getAlignment(member.data));623    alignment = std::max(alignment, getAlignment(member.data));624  }625  // If the size of the record (the capstone's offset) is not a multiple of the626  // record's alignment, it must be packed.627  if (!members.back().offset.isMultipleOf(alignment))628    packed = true;629  // If the non-virtual sub-object is not a multiple of the non-virtual630  // sub-object's alignment, it must be packed.  We cannot have a packed631  // non-virtual sub-object and an unpacked complete object or vise versa.632  if (!nvSize.isMultipleOf(nvAlignment))633    packed = true;634  // Update the alignment of the sentinel.635  if (!packed)636    members.back().data = getUIntNType(astContext.toBits(alignment));637}638 639void CIRRecordLowering::insertPadding() {640  std::vector<std::pair<CharUnits, CharUnits>> padding;641  CharUnits size = CharUnits::Zero();642  for (const MemberInfo &member : members) {643    if (!member.data)644      continue;645    CharUnits offset = member.offset;646    assert(offset >= size);647    // Insert padding if we need to.648    if (offset !=649        size.alignTo(packed ? CharUnits::One() : getAlignment(member.data)))650      padding.push_back(std::make_pair(size, offset - size));651    size = offset + getSize(member.data);652  }653  if (padding.empty())654    return;655  padded = true;656  // Add the padding to the Members list and sort it.657  for (const std::pair<CharUnits, CharUnits> &paddingPair : padding)658    members.push_back(makeStorageInfo(paddingPair.first,659                                      getByteArrayType(paddingPair.second)));660  llvm::stable_sort(members);661}662 663std::unique_ptr<CIRGenRecordLayout>664CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {665  CIRRecordLowering lowering(*this, rd, /*packed=*/false);666  assert(ty->isIncomplete() && "recomputing record layout?");667  lowering.lower(/*nonVirtualBaseType=*/false);668 669  // If we're in C++, compute the base subobject type.670  cir::RecordType baseTy;671  if (llvm::isa<CXXRecordDecl>(rd) && !rd->isUnion() &&672      !rd->hasAttr<FinalAttr>()) {673    baseTy = *ty;674    if (lowering.astRecordLayout.getNonVirtualSize() !=675        lowering.astRecordLayout.getSize()) {676      CIRRecordLowering baseLowering(*this, rd, /*Packed=*/lowering.packed);677      baseLowering.lower(/*NonVirtualBaseType=*/true);678      std::string baseIdentifier = getRecordTypeName(rd, ".base");679      baseTy = builder.getCompleteNamedRecordType(680          baseLowering.fieldTypes, baseLowering.packed, baseLowering.padded,681          baseIdentifier);682      // TODO(cir): add something like addRecordTypeName683 684      // BaseTy and Ty must agree on their packedness for getCIRFieldNo to work685      // on both of them with the same index.686      assert(lowering.packed == baseLowering.packed &&687             "Non-virtual and complete types must agree on packedness");688    }689  }690 691  // Fill in the record *after* computing the base type.  Filling in the body692  // signifies that the type is no longer opaque and record layout is complete,693  // but we may need to recursively layout rd while laying D out as a base type.694  assert(!cir::MissingFeatures::astRecordDeclAttr());695  ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);696 697  auto rl = std::make_unique<CIRGenRecordLayout>(698      ty ? *ty : cir::RecordType{}, baseTy ? baseTy : cir::RecordType{},699      (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);700 701  rl->nonVirtualBases.swap(lowering.nonVirtualBases);702  rl->completeObjectVirtualBases.swap(lowering.virtualBases);703 704  // Add all the field numbers.705  rl->fieldIdxMap.swap(lowering.fieldIdxMap);706 707  rl->bitFields.swap(lowering.bitFields);708 709  // Dump the layout, if requested.710  if (getASTContext().getLangOpts().DumpRecordLayouts) {711    llvm::outs() << "\n*** Dumping CIRgen Record Layout\n";712    llvm::outs() << "Record: ";713    rd->dump(llvm::outs());714    llvm::outs() << "\nLayout: ";715    rl->print(llvm::outs());716  }717 718  // TODO: implement verification719  return rl;720}721 722void CIRGenRecordLayout::print(raw_ostream &os) const {723  os << "<CIRecordLayout\n";724  os << "   CIR Type:" << completeObjectType << "\n";725  if (baseSubobjectType)726    os << "   NonVirtualBaseCIRType:" << baseSubobjectType << "\n";727  os << "   IsZeroInitializable:" << zeroInitializable << "\n";728  os << "   BitFields:[\n";729  std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;730  for (auto &[decl, info] : bitFields) {731    const RecordDecl *rd = decl->getParent();732    unsigned index = 0;733    for (RecordDecl::field_iterator it = rd->field_begin(); *it != decl; ++it)734      ++index;735    bitInfo.push_back(std::make_pair(index, &info));736  }737  llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());738  for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {739    os.indent(4);740    info.second->print(os);741    os << "\n";742  }743  os << "   ]>\n";744}745 746void CIRGenBitFieldInfo::print(raw_ostream &os) const {747  os << "<CIRBitFieldInfo" << " name:" << name << " offset:" << offset748     << " size:" << size << " isSigned:" << isSigned749     << " storageSize:" << storageSize750     << " storageOffset:" << storageOffset.getQuantity()751     << " volatileOffset:" << volatileOffset752     << " volatileStorageSize:" << volatileStorageSize753     << " volatileStorageOffset:" << volatileStorageOffset.getQuantity() << ">";754}755 756void CIRGenRecordLayout::dump() const { print(llvm::errs()); }757 758void CIRGenBitFieldInfo::dump() const { print(llvm::errs()); }759 760void CIRRecordLowering::lowerUnion() {761  CharUnits layoutSize = astRecordLayout.getSize();762  mlir::Type storageType = nullptr;763  bool seenNamedMember = false;764 765  // Iterate through the fields setting bitFieldInfo and the Fields array. Also766  // locate the "most appropriate" storage type.767  for (const FieldDecl *field : recordDecl->fields()) {768    mlir::Type fieldType;769    if (field->isBitField()) {770      if (field->isZeroLengthBitField())771        continue;772      fieldType = getBitfieldStorageType(field->getBitWidthValue());773      setBitFieldInfo(field, CharUnits::Zero(), fieldType);774    } else {775      fieldType = getStorageType(field);776    }777 778    // This maps a field to its index. For unions, the index is always 0.779    fieldIdxMap[field->getCanonicalDecl()] = 0;780 781    // Compute zero-initializable status.782    // This union might not be zero initialized: it may contain a pointer to783    // data member which might have some exotic initialization sequence.784    // If this is the case, then we ought not to try and come up with a "better"785    // type, it might not be very easy to come up with a Constant which786    // correctly initializes it.787    if (!seenNamedMember) {788      seenNamedMember = field->getIdentifier();789      if (!seenNamedMember)790        if (const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())791          seenNamedMember = fieldRD->findFirstNamedDataMember();792      if (seenNamedMember && !isZeroInitializable(field)) {793        zeroInitializable = zeroInitializableAsBase = false;794        storageType = fieldType;795      }796    }797 798    // Because our union isn't zero initializable, we won't be getting a better799    // storage type.800    if (!zeroInitializable)801      continue;802 803    // Conditionally update our storage type if we've got a new "better" one.804    if (!storageType || getAlignment(fieldType) > getAlignment(storageType) ||805        (getAlignment(fieldType) == getAlignment(storageType) &&806         getSize(fieldType) > getSize(storageType)))807      storageType = fieldType;808 809    // NOTE(cir): Track all union member's types, not just the largest one. It810    // allows for proper type-checking and retain more info for analisys.811    fieldTypes.push_back(fieldType);812  }813 814  if (!storageType)815    cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),816                                       "No-storage Union NYI");817 818  if (layoutSize < getSize(storageType))819    storageType = getByteArrayType(layoutSize);820  else821    appendPaddingBytes(layoutSize - getSize(storageType));822 823  // Set packed if we need it.824  if (!layoutSize.isMultipleOf(getAlignment(storageType)))825    packed = true;826}827 828bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,829                                      const CXXRecordDecl *query) {830  const ASTRecordLayout &declLayout = astContext.getASTRecordLayout(decl);831  if (declLayout.isPrimaryBaseVirtual() && declLayout.getPrimaryBase() == query)832    return false;833  for (const auto &base : decl->bases())834    if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))835      return false;836  return true;837}838 839/// The AAPCS that defines that, when possible, bit-fields should840/// be accessed using containers of the declared type width:841/// When a volatile bit-field is read, and its container does not overlap with842/// any non-bit-field member or any zero length bit-field member, its container843/// must be read exactly once using the access width appropriate to the type of844/// the container. When a volatile bit-field is written, and its container does845/// not overlap with any non-bit-field member or any zero-length bit-field846/// member, its container must be read exactly once and written exactly once847/// using the access width appropriate to the type of the container. The two848/// accesses are not atomic.849///850/// Enforcing the width restriction can be disabled using851/// -fno-aapcs-bitfield-width.852void CIRRecordLowering::computeVolatileBitfields() {853  if (!isAAPCS() ||854      !cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth)855    return;856 857  for (auto &[field, info] : bitFields) {858    mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType());859 860    if (astContext.toBits(astRecordLayout.getAlignment()) <861        getSizeInBits(resLTy).getQuantity())862      continue;863 864    // CIRRecordLowering::setBitFieldInfo() pre-adjusts the bit-field offsets865    // for big-endian targets, but it assumes a container of width866    // info.storageSize. Since AAPCS uses a different container size (width867    // of the type), we first undo that calculation here and redo it once868    // the bit-field offset within the new container is calculated.869    const unsigned oldOffset =870        isBigEndian() ? info.storageSize - (info.offset + info.size)871                      : info.offset;872    // Offset to the bit-field from the beginning of the struct.873    const unsigned absoluteOffset =874        astContext.toBits(info.storageOffset) + oldOffset;875 876    // Container size is the width of the bit-field type.877    const unsigned storageSize = getSizeInBits(resLTy).getQuantity();878    // Nothing to do if the access uses the desired879    // container width and is naturally aligned.880    if (info.storageSize == storageSize && (oldOffset % storageSize == 0))881      continue;882 883    // Offset within the container.884    unsigned offset = absoluteOffset & (storageSize - 1);885    // Bail out if an aligned load of the container cannot cover the entire886    // bit-field. This can happen for example, if the bit-field is part of a887    // packed struct. AAPCS does not define access rules for such cases, we let888    // clang to follow its own rules.889    if (offset + info.size > storageSize)890      continue;891 892    // Re-adjust offsets for big-endian targets.893    if (isBigEndian())894      offset = storageSize - (offset + info.size);895 896    const CharUnits storageOffset =897        astContext.toCharUnitsFromBits(absoluteOffset & ~(storageSize - 1));898    const CharUnits end = storageOffset +899                          astContext.toCharUnitsFromBits(storageSize) -900                          CharUnits::One();901 902    const ASTRecordLayout &layout =903        astContext.getASTRecordLayout(field->getParent());904    // If we access outside memory outside the record, than bail out.905    const CharUnits recordSize = layout.getSize();906    if (end >= recordSize)907      continue;908 909    // Bail out if performing this load would access non-bit-fields members.910    bool conflict = false;911    for (const auto *f : recordDecl->fields()) {912      // Allow sized bit-fields overlaps.913      if (f->isBitField() && !f->isZeroLengthBitField())914        continue;915 916      const CharUnits fOffset = astContext.toCharUnitsFromBits(917          layout.getFieldOffset(f->getFieldIndex()));918 919      // As C11 defines, a zero sized bit-field defines a barrier, so920      // fields after and before it should be race condition free.921      // The AAPCS acknowledges it and imposes no restritions when the922      // natural container overlaps a zero-length bit-field.923      if (f->isZeroLengthBitField()) {924        if (end > fOffset && storageOffset < fOffset) {925          conflict = true;926          break;927        }928      }929 930      const CharUnits fEnd =931          fOffset +932          astContext.toCharUnitsFromBits(933              getSizeInBits(cirGenTypes.convertTypeForMem(f->getType()))934                  .getQuantity()) -935          CharUnits::One();936      // If no overlap, continue.937      if (end < fOffset || fEnd < storageOffset)938        continue;939 940      // The desired load overlaps a non-bit-field member, bail out.941      conflict = true;942      break;943    }944 945    if (conflict)946      continue;947    // Write the new bit-field access parameters.948    // As the storage offset now is defined as the number of elements from the949    // start of the structure, we should divide the Offset by the element size.950    info.volatileStorageOffset =951        storageOffset /952        astContext.toCharUnitsFromBits(storageSize).getQuantity();953    info.volatileStorageSize = storageSize;954    info.volatileOffset = offset;955  }956}957 958void CIRRecordLowering::accumulateBases() {959  // If we've got a primary virtual base, we need to add it with the bases.960  if (astRecordLayout.isPrimaryBaseVirtual()) {961    const CXXRecordDecl *baseDecl = astRecordLayout.getPrimaryBase();962    members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::Base,963                                 getStorageType(baseDecl), baseDecl));964  }965 966  // Accumulate the non-virtual bases.967  for (const auto &base : cxxRecordDecl->bases()) {968    if (base.isVirtual())969      continue;970    // Bases can be zero-sized even if not technically empty if they971    // contain only a trailing array member.972    const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();973    if (!baseDecl->isEmpty() &&974        !astContext.getASTRecordLayout(baseDecl).getNonVirtualSize().isZero()) {975      members.push_back(MemberInfo(astRecordLayout.getBaseClassOffset(baseDecl),976                                   MemberInfo::InfoKind::Base,977                                   getStorageType(baseDecl), baseDecl));978    }979  }980}981 982void CIRRecordLowering::accumulateVBases() {983  for (const auto &base : cxxRecordDecl->vbases()) {984    const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();985    if (isEmptyRecordForLayout(astContext, base.getType()))986      continue;987    CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);988    // If the vbase is a primary virtual base of some base, then it doesn't989    // get its own storage location but instead lives inside of that base.990    if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&991        !hasOwnStorage(cxxRecordDecl, baseDecl)) {992      members.push_back(993          MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr, baseDecl));994      continue;995    }996    // If we've got a vtordisp, add it as a storage type.997    if (astRecordLayout.getVBaseOffsetsMap()998            .find(baseDecl)999            ->second.hasVtorDisp())1000      members.push_back(makeStorageInfo(offset - CharUnits::fromQuantity(4),1001                                        getUIntNType(32)));1002    members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,1003                                 getStorageType(baseDecl), baseDecl));1004  }1005}1006 1007void CIRRecordLowering::accumulateVPtrs() {1008  if (astRecordLayout.hasOwnVFPtr())1009    members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,1010                                 getVFPtrType()));1011 1012  if (astRecordLayout.hasOwnVBPtr())1013    cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),1014                                       "accumulateVPtrs: hasOwnVBPtr");1015}1016 1017mlir::Type CIRRecordLowering::getVFPtrType() {1018  return cir::VPtrType::get(builder.getContext());1019}1020