brintos

brintos / llvm-project-archived public Read only

0
0
Text · 52.4 KiB · c98d9bb Raw
1316 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 dealing with C++ code generation of classes10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenCXXABI.h"14#include "CIRGenFunction.h"15#include "CIRGenValue.h"16 17#include "clang/AST/EvaluatedExprVisitor.h"18#include "clang/AST/ExprCXX.h"19#include "clang/AST/RecordLayout.h"20#include "clang/AST/Type.h"21#include "clang/CIR/Dialect/IR/CIRDialect.h"22#include "clang/CIR/MissingFeatures.h"23 24using namespace clang;25using namespace clang::CIRGen;26 27/// Checks whether the given constructor is a valid subject for the28/// complete-to-base constructor delegation optimization, i.e. emitting the29/// complete constructor as a simple call to the base constructor.30bool CIRGenFunction::isConstructorDelegationValid(31    const CXXConstructorDecl *ctor) {32  // Currently we disable the optimization for classes with virtual bases33  // because (1) the address of parameter variables need to be consistent across34  // all initializers but (2) the delegate function call necessarily creates a35  // second copy of the parameter variable.36  //37  // The limiting example (purely theoretical AFAIK):38  //   struct A { A(int &c) { c++; } };39  //   struct A : virtual A {40  //     B(int count) : A(count) { printf("%d\n", count); }41  //   };42  // ...although even this example could in principle be emitted as a delegation43  // since the address of the parameter doesn't escape.44  if (ctor->getParent()->getNumVBases())45    return false;46 47  // We also disable the optimization for variadic functions because it's48  // impossible to "re-pass" varargs.49  if (ctor->getType()->castAs<FunctionProtoType>()->isVariadic())50    return false;51 52  // FIXME: Decide if we can do a delegation of a delegating constructor.53  if (ctor->isDelegatingConstructor())54    return false;55 56  return true;57}58 59static void emitLValueForAnyFieldInitialization(CIRGenFunction &cgf,60                                                CXXCtorInitializer *memberInit,61                                                LValue &lhs) {62  FieldDecl *field = memberInit->getAnyMember();63  if (memberInit->isIndirectMemberInitializer()) {64    // If we are initializing an anonymous union field, drill down to the field.65    IndirectFieldDecl *indirectField = memberInit->getIndirectMember();66    for (const auto *nd : indirectField->chain()) {67      auto *fd = cast<clang::FieldDecl>(nd);68      lhs = cgf.emitLValueForFieldInitialization(lhs, fd, fd->getName());69    }70  } else {71    lhs = cgf.emitLValueForFieldInitialization(lhs, field, field->getName());72  }73}74 75static void emitMemberInitializer(CIRGenFunction &cgf,76                                  const CXXRecordDecl *classDecl,77                                  CXXCtorInitializer *memberInit,78                                  const CXXConstructorDecl *constructor,79                                  FunctionArgList &args) {80  assert(memberInit->isAnyMemberInitializer() &&81         "Must have member initializer!");82  assert(memberInit->getInit() && "Must have initializer!");83 84  assert(!cir::MissingFeatures::generateDebugInfo());85 86  // non-static data member initializers87  FieldDecl *field = memberInit->getAnyMember();88  QualType fieldType = field->getType();89 90  mlir::Value thisPtr = cgf.loadCXXThis();91  CanQualType recordTy = cgf.getContext().getCanonicalTagType(classDecl);92 93  // If a base constructor is being emitted, create an LValue that has the94  // non-virtual alignment.95  LValue lhs = (cgf.curGD.getCtorType() == Ctor_Base)96                   ? cgf.makeNaturalAlignPointeeAddrLValue(thisPtr, recordTy)97                   : cgf.makeNaturalAlignAddrLValue(thisPtr, recordTy);98 99  emitLValueForAnyFieldInitialization(cgf, memberInit, lhs);100 101  // Special case: If we are in a copy or move constructor, and we are copying102  // an array off PODs or classes with trivial copy constructors, ignore the AST103  // and perform the copy we know is equivalent.104  // FIXME: This is hacky at best... if we had a bit more explicit information105  // in the AST, we could generalize it more easily.106  const ConstantArrayType *array =107      cgf.getContext().getAsConstantArrayType(fieldType);108  if (array && constructor->isDefaulted() &&109      constructor->isCopyOrMoveConstructor()) {110    QualType baseElementTy = cgf.getContext().getBaseElementType(array);111    // NOTE(cir): CodeGen allows record types to be memcpy'd if applicable,112    // whereas ClangIR wants to represent all object construction explicitly.113    if (!baseElementTy->isRecordType()) {114      unsigned srcArgIndex =115          cgf.cgm.getCXXABI().getSrcArgforCopyCtor(constructor, args);116      cir::LoadOp srcPtr = cgf.getBuilder().createLoad(117          cgf.getLoc(memberInit->getSourceLocation()),118          cgf.getAddrOfLocalVar(args[srcArgIndex]));119      LValue thisRhslv = cgf.makeNaturalAlignAddrLValue(srcPtr, recordTy);120      LValue src = cgf.emitLValueForFieldInitialization(thisRhslv, field,121                                                        field->getName());122 123      // Copy the aggregate.124      cgf.emitAggregateCopy(lhs, src, fieldType,125                            cgf.getOverlapForFieldInit(field),126                            lhs.isVolatileQualified());127      // Ensure that we destroy the objects if an exception is thrown later in128      // the constructor.129      QualType::DestructionKind dtorKind = fieldType.isDestructedType();130      assert(!cgf.needsEHCleanup(dtorKind) &&131             "Arrays of non-record types shouldn't need EH cleanup");132      return;133    }134  }135 136  cgf.emitInitializerForField(field, lhs, memberInit->getInit());137}138 139static bool isInitializerOfDynamicClass(const CXXCtorInitializer *baseInit) {140  const Type *baseType = baseInit->getBaseClass();141  const auto *baseClassDecl = baseType->castAsCXXRecordDecl();142  return baseClassDecl->isDynamicClass();143}144 145namespace {146/// Call the destructor for a direct base class.147struct CallBaseDtor final : EHScopeStack::Cleanup {148  const CXXRecordDecl *baseClass;149  bool baseIsVirtual;150  CallBaseDtor(const CXXRecordDecl *base, bool baseIsVirtual)151      : baseClass(base), baseIsVirtual(baseIsVirtual) {}152 153  void emit(CIRGenFunction &cgf) override {154    const CXXRecordDecl *derivedClass =155        cast<CXXMethodDecl>(cgf.curFuncDecl)->getParent();156 157    const CXXDestructorDecl *d = baseClass->getDestructor();158    // We are already inside a destructor, so presumably the object being159    // destroyed should have the expected type.160    QualType thisTy = d->getFunctionObjectParameterType();161    assert(cgf.currSrcLoc && "expected source location");162    Address addr = cgf.getAddressOfDirectBaseInCompleteClass(163        *cgf.currSrcLoc, cgf.loadCXXThisAddress(), derivedClass, baseClass,164        baseIsVirtual);165    cgf.emitCXXDestructorCall(d, Dtor_Base, baseIsVirtual,166                              /*delegating=*/false, addr, thisTy);167  }168};169 170/// A visitor which checks whether an initializer uses 'this' in a171/// way which requires the vtable to be properly set.172struct DynamicThisUseChecker173    : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {174  using super = ConstEvaluatedExprVisitor<DynamicThisUseChecker>;175 176  bool usesThis = false;177 178  DynamicThisUseChecker(const ASTContext &c) : super(c) {}179 180  // Black-list all explicit and implicit references to 'this'.181  //182  // Do we need to worry about external references to 'this' derived183  // from arbitrary code? If so, then anything which runs arbitrary184  // external code might potentially access the vtable.185  void VisitCXXThisExpr(const CXXThisExpr *e) { usesThis = true; }186};187} // end anonymous namespace188 189static bool baseInitializerUsesThis(ASTContext &c, const Expr *init) {190  DynamicThisUseChecker checker(c);191  checker.Visit(init);192  return checker.usesThis;193}194 195/// Gets the address of a direct base class within a complete object.196/// This should only be used for (1) non-virtual bases or (2) virtual bases197/// when the type is known to be complete (e.g. in complete destructors).198///199/// The object pointed to by 'thisAddr' is assumed to be non-null.200Address CIRGenFunction::getAddressOfDirectBaseInCompleteClass(201    mlir::Location loc, Address thisAddr, const CXXRecordDecl *derived,202    const CXXRecordDecl *base, bool baseIsVirtual) {203  // 'thisAddr' must be a pointer (in some address space) to Derived.204  assert(thisAddr.getElementType() == convertType(derived));205 206  // Compute the offset of the virtual base.207  CharUnits offset;208  const ASTRecordLayout &layout = getContext().getASTRecordLayout(derived);209  if (baseIsVirtual)210    offset = layout.getVBaseClassOffset(base);211  else212    offset = layout.getBaseClassOffset(base);213 214  return builder.createBaseClassAddr(loc, thisAddr, convertType(base),215                                     offset.getQuantity(),216                                     /*assumeNotNull=*/true);217}218 219void CIRGenFunction::emitBaseInitializer(mlir::Location loc,220                                         const CXXRecordDecl *classDecl,221                                         CXXCtorInitializer *baseInit) {222  assert(curFuncDecl && "loading 'this' without a func declaration?");223  assert(isa<CXXMethodDecl>(curFuncDecl));224 225  assert(baseInit->isBaseInitializer() && "Must have base initializer!");226 227  Address thisPtr = loadCXXThisAddress();228 229  const Type *baseType = baseInit->getBaseClass();230  const auto *baseClassDecl = baseType->castAsCXXRecordDecl();231 232  bool isBaseVirtual = baseInit->isBaseVirtual();233 234  // If the initializer for the base (other than the constructor235  // itself) accesses 'this' in any way, we need to initialize the236  // vtables.237  if (baseInitializerUsesThis(getContext(), baseInit->getInit()))238    initializeVTablePointers(loc, classDecl);239 240  // We can pretend to be a complete class because it only matters for241  // virtual bases, and we only do virtual bases for complete ctors.242  Address v = getAddressOfDirectBaseInCompleteClass(243      loc, thisPtr, classDecl, baseClassDecl, isBaseVirtual);244  assert(!cir::MissingFeatures::aggValueSlotGC());245  AggValueSlot aggSlot = AggValueSlot::forAddr(246      v, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::IsNotAliased,247      getOverlapForBaseInit(classDecl, baseClassDecl, isBaseVirtual));248 249  emitAggExpr(baseInit->getInit(), aggSlot);250 251  assert(!cir::MissingFeatures::requiresCleanups());252}253 254/// This routine generates necessary code to initialize base classes and255/// non-static data members belonging to this constructor.256void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd,257                                      CXXCtorType ctorType,258                                      FunctionArgList &args) {259  if (cd->isDelegatingConstructor()) {260    emitDelegatingCXXConstructorCall(cd, args);261    return;262  }263 264  const CXXRecordDecl *classDecl = cd->getParent();265 266  // Virtual base initializers aren't needed if:267  // - This is a base ctor variant268  // - There are no vbases269  // - The class is abstract, so a complete object of it cannot be constructed270  //271  // The check for an abstract class is necessary because sema may not have272  // marked virtual base destructors referenced.273  bool constructVBases = ctorType != Ctor_Base &&274                         classDecl->getNumVBases() != 0 &&275                         !classDecl->isAbstract();276  if (constructVBases &&277      !cgm.getTarget().getCXXABI().hasConstructorVariants()) {278    cgm.errorNYI(cd->getSourceRange(),279                 "emitCtorPrologue: virtual base without variants");280    return;281  }282 283  // Create three separate ranges for the different types of initializers.284  auto allInits = cd->inits();285 286  // Find the boundaries between the three groups.287  auto virtualBaseEnd = std::find_if(288      allInits.begin(), allInits.end(), [](const CXXCtorInitializer *Init) {289        return !(Init->isBaseInitializer() && Init->isBaseVirtual());290      });291 292  auto nonVirtualBaseEnd = std::find_if(virtualBaseEnd, allInits.end(),293                                        [](const CXXCtorInitializer *Init) {294                                          return !Init->isBaseInitializer();295                                        });296 297  // Create the three ranges.298  auto virtualBaseInits = llvm::make_range(allInits.begin(), virtualBaseEnd);299  auto nonVirtualBaseInits =300      llvm::make_range(virtualBaseEnd, nonVirtualBaseEnd);301  auto memberInits = llvm::make_range(nonVirtualBaseEnd, allInits.end());302 303  const mlir::Value oldThisValue = cxxThisValue;304 305  auto emitInitializer = [&](CXXCtorInitializer *baseInit) {306    if (cgm.getCodeGenOpts().StrictVTablePointers &&307        cgm.getCodeGenOpts().OptimizationLevel > 0 &&308        isInitializerOfDynamicClass(baseInit)) {309      // It's OK to continue after emitting the error here. The missing code310      // just "launders" the 'this' pointer.311      cgm.errorNYI(cd->getSourceRange(),312                   "emitCtorPrologue: strict vtable pointers for vbase");313    }314    emitBaseInitializer(getLoc(cd->getBeginLoc()), classDecl, baseInit);315  };316 317  // Process virtual base initializers.318  for (CXXCtorInitializer *virtualBaseInit : virtualBaseInits) {319    if (!constructVBases)320      continue;321    emitInitializer(virtualBaseInit);322  }323 324  assert(!cir::MissingFeatures::msabi());325 326  // Then, non-virtual base initializers.327  for (CXXCtorInitializer *nonVirtualBaseInit : nonVirtualBaseInits) {328    assert(!nonVirtualBaseInit->isBaseVirtual());329    emitInitializer(nonVirtualBaseInit);330  }331 332  cxxThisValue = oldThisValue;333 334  initializeVTablePointers(getLoc(cd->getBeginLoc()), classDecl);335 336  // Finally, initialize class members.337  FieldConstructionScope fcs(*this, loadCXXThisAddress());338  // Classic codegen uses a special class to attempt to replace member339  // initializers with memcpy. We could possibly defer that to the340  // lowering or optimization phases to keep the memory accesses more341  // explicit. For now, we don't insert memcpy at all.342  assert(!cir::MissingFeatures::ctorMemcpyizer());343  for (CXXCtorInitializer *member : memberInits) {344    assert(!member->isBaseInitializer());345    assert(member->isAnyMemberInitializer() &&346           "Delegating initializer on non-delegating constructor");347    emitMemberInitializer(*this, cd->getParent(), member, cd, args);348  }349}350 351static Address applyNonVirtualAndVirtualOffset(352    mlir::Location loc, CIRGenFunction &cgf, Address addr,353    CharUnits nonVirtualOffset, mlir::Value virtualOffset,354    const CXXRecordDecl *derivedClass, const CXXRecordDecl *nearestVBase,355    mlir::Type baseValueTy = {}, bool assumeNotNull = true) {356  // Assert that we have something to do.357  assert(!nonVirtualOffset.isZero() || virtualOffset != nullptr);358 359  // Compute the offset from the static and dynamic components.360  mlir::Value baseOffset;361  if (!nonVirtualOffset.isZero()) {362    if (virtualOffset) {363      cgf.cgm.errorNYI(364          loc,365          "applyNonVirtualAndVirtualOffset: virtual and non-virtual offset");366      return Address::invalid();367    } else {368      assert(baseValueTy && "expected base type");369      // If no virtualOffset is present this is the final stop.370      return cgf.getBuilder().createBaseClassAddr(371          loc, addr, baseValueTy, nonVirtualOffset.getQuantity(),372          assumeNotNull);373    }374  } else {375    baseOffset = virtualOffset;376  }377 378  // Apply the base offset.  cir.ptr_stride adjusts by a number of elements,379  // not bytes.  So the pointer must be cast to a byte pointer and back.380 381  mlir::Value ptr = addr.getPointer();382  mlir::Type charPtrType = cgf.cgm.uInt8PtrTy;383  mlir::Value charPtr = cgf.getBuilder().createBitcast(ptr, charPtrType);384  mlir::Value adjusted = cir::PtrStrideOp::create(385      cgf.getBuilder(), loc, charPtrType, charPtr, baseOffset);386  ptr = cgf.getBuilder().createBitcast(adjusted, ptr.getType());387 388  // If we have a virtual component, the alignment of the result will389  // be relative only to the known alignment of that vbase.390  CharUnits alignment;391  if (virtualOffset) {392    assert(nearestVBase && "virtual offset without vbase?");393    alignment = cgf.cgm.getVBaseAlignment(addr.getAlignment(), derivedClass,394                                          nearestVBase);395  } else {396    alignment = addr.getAlignment();397  }398  alignment = alignment.alignmentAtOffset(nonVirtualOffset);399 400  return Address(ptr, alignment);401}402 403void CIRGenFunction::initializeVTablePointer(mlir::Location loc,404                                             const VPtr &vptr) {405  // Compute the address point.406  mlir::Value vtableAddressPoint =407      cgm.getCXXABI().getVTableAddressPointInStructor(408          *this, vptr.vtableClass, vptr.base, vptr.nearestVBase);409 410  if (!vtableAddressPoint)411    return;412 413  // Compute where to store the address point.414  mlir::Value virtualOffset{};415  CharUnits nonVirtualOffset = CharUnits::Zero();416 417  mlir::Type baseValueTy;418  if (cgm.getCXXABI().isVirtualOffsetNeededForVTableField(*this, vptr)) {419    // We need to use the virtual base offset offset because the virtual base420    // might have a different offset in the most derived class.421    virtualOffset = cgm.getCXXABI().getVirtualBaseClassOffset(422        loc, *this, loadCXXThisAddress(), vptr.vtableClass, vptr.nearestVBase);423    nonVirtualOffset = vptr.offsetFromNearestVBase;424  } else {425    // We can just use the base offset in the complete class.426    nonVirtualOffset = vptr.base.getBaseOffset();427    baseValueTy =428        convertType(getContext().getCanonicalTagType(vptr.base.getBase()));429  }430 431  // Apply the offsets.432  Address classAddr = loadCXXThisAddress();433  if (!nonVirtualOffset.isZero() || virtualOffset) {434    classAddr = applyNonVirtualAndVirtualOffset(435        loc, *this, classAddr, nonVirtualOffset, virtualOffset,436        vptr.vtableClass, vptr.nearestVBase, baseValueTy);437  }438 439  // Finally, store the address point. Use the same CIR types as the field.440  //441  // vtable field is derived from `this` pointer, therefore they should be in442  // the same addr space.443  assert(!cir::MissingFeatures::addressSpace());444  auto vtablePtr = cir::VTableGetVPtrOp::create(445      builder, loc, builder.getPtrToVPtrType(), classAddr.getPointer());446  Address vtableField = Address(vtablePtr, classAddr.getAlignment());447  builder.createStore(loc, vtableAddressPoint, vtableField);448  assert(!cir::MissingFeatures::opTBAA());449  assert(!cir::MissingFeatures::createInvariantGroup());450}451 452void CIRGenFunction::initializeVTablePointers(mlir::Location loc,453                                              const CXXRecordDecl *rd) {454  // Ignore classes without a vtable.455  if (!rd->isDynamicClass())456    return;457 458  // Initialize the vtable pointers for this class and all of its bases.459  if (cgm.getCXXABI().doStructorsInitializeVPtrs(rd))460    for (const auto &vptr : getVTablePointers(rd))461      initializeVTablePointer(loc, vptr);462 463  if (rd->getNumVBases())464    cgm.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, rd);465}466 467CIRGenFunction::VPtrsVector468CIRGenFunction::getVTablePointers(const CXXRecordDecl *vtableClass) {469  CIRGenFunction::VPtrsVector vptrsResult;470  VisitedVirtualBasesSetTy vbases;471  getVTablePointers(BaseSubobject(vtableClass, CharUnits::Zero()),472                    /*NearestVBase=*/nullptr,473                    /*OffsetFromNearestVBase=*/CharUnits::Zero(),474                    /*BaseIsNonVirtualPrimaryBase=*/false, vtableClass, vbases,475                    vptrsResult);476  return vptrsResult;477}478 479void CIRGenFunction::getVTablePointers(BaseSubobject base,480                                       const CXXRecordDecl *nearestVBase,481                                       CharUnits offsetFromNearestVBase,482                                       bool baseIsNonVirtualPrimaryBase,483                                       const CXXRecordDecl *vtableClass,484                                       VisitedVirtualBasesSetTy &vbases,485                                       VPtrsVector &vptrs) {486  // If this base is a non-virtual primary base the address point has already487  // been set.488  if (!baseIsNonVirtualPrimaryBase) {489    // Initialize the vtable pointer for this base.490    VPtr vptr = {base, nearestVBase, offsetFromNearestVBase, vtableClass};491    vptrs.push_back(vptr);492  }493 494  const CXXRecordDecl *rd = base.getBase();495 496  for (const auto &nextBase : rd->bases()) {497    const auto *baseDecl =498        cast<CXXRecordDecl>(nextBase.getType()->castAs<RecordType>()->getDecl())499            ->getDefinitionOrSelf();500 501    // Ignore classes without a vtable.502    if (!baseDecl->isDynamicClass())503      continue;504 505    CharUnits baseOffset;506    CharUnits baseOffsetFromNearestVBase;507    bool baseDeclIsNonVirtualPrimaryBase;508    const CXXRecordDecl *nextBaseDecl;509 510    if (nextBase.isVirtual()) {511      // Check if we've visited this virtual base before.512      if (!vbases.insert(baseDecl).second)513        continue;514 515      const ASTRecordLayout &layout =516          getContext().getASTRecordLayout(vtableClass);517 518      nextBaseDecl = baseDecl;519      baseOffset = layout.getVBaseClassOffset(baseDecl);520      baseOffsetFromNearestVBase = CharUnits::Zero();521      baseDeclIsNonVirtualPrimaryBase = false;522    } else {523      const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd);524 525      nextBaseDecl = nearestVBase;526      baseOffset = base.getBaseOffset() + layout.getBaseClassOffset(baseDecl);527      baseOffsetFromNearestVBase =528          offsetFromNearestVBase + layout.getBaseClassOffset(baseDecl);529      baseDeclIsNonVirtualPrimaryBase = layout.getPrimaryBase() == baseDecl;530    }531 532    getVTablePointers(BaseSubobject(baseDecl, baseOffset), nextBaseDecl,533                      baseOffsetFromNearestVBase,534                      baseDeclIsNonVirtualPrimaryBase, vtableClass, vbases,535                      vptrs);536  }537}538 539Address CIRGenFunction::loadCXXThisAddress() {540  assert(curFuncDecl && "loading 'this' without a func declaration?");541  assert(isa<CXXMethodDecl>(curFuncDecl));542 543  // Lazily compute CXXThisAlignment.544  if (cxxThisAlignment.isZero()) {545    // Just use the best known alignment for the parent.546    // TODO: if we're currently emitting a complete-object ctor/dtor, we can547    // always use the complete-object alignment.548    auto rd = cast<CXXMethodDecl>(curFuncDecl)->getParent();549    cxxThisAlignment = cgm.getClassPointerAlignment(rd);550  }551 552  return Address(loadCXXThis(), cxxThisAlignment);553}554 555void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs,556                                             Expr *init) {557  QualType fieldType = field->getType();558  switch (getEvaluationKind(fieldType)) {559  case cir::TEK_Scalar:560    if (lhs.isSimple()) {561      emitExprAsInit(init, field, lhs, false);562    } else {563      RValue rhs = RValue::get(emitScalarExpr(init));564      emitStoreThroughLValue(rhs, lhs);565    }566    break;567  case cir::TEK_Complex:568    emitComplexExprIntoLValue(init, lhs, /*isInit=*/true);569    break;570  case cir::TEK_Aggregate: {571    assert(!cir::MissingFeatures::aggValueSlotGC());572    assert(!cir::MissingFeatures::sanitizers());573    AggValueSlot slot = AggValueSlot::forLValue(574        lhs, AggValueSlot::IsDestructed, AggValueSlot::IsNotAliased,575        getOverlapForFieldInit(field), AggValueSlot::IsNotZeroed);576    emitAggExpr(init, slot);577    break;578  }579  }580 581  // Ensure that we destroy this object if an exception is thrown later in the582  // constructor.583  QualType::DestructionKind dtorKind = fieldType.isDestructedType();584  (void)dtorKind;585  assert(!cir::MissingFeatures::requiresCleanups());586}587 588CharUnits589CIRGenModule::getDynamicOffsetAlignment(CharUnits actualBaseAlign,590                                        const CXXRecordDecl *baseDecl,591                                        CharUnits expectedTargetAlign) {592  // If the base is an incomplete type (which is, alas, possible with593  // member pointers), be pessimistic.594  if (!baseDecl->isCompleteDefinition())595    return std::min(actualBaseAlign, expectedTargetAlign);596 597  const ASTRecordLayout &baseLayout =598      getASTContext().getASTRecordLayout(baseDecl);599  CharUnits expectedBaseAlign = baseLayout.getNonVirtualAlignment();600 601  // If the class is properly aligned, assume the target offset is, too.602  //603  // This actually isn't necessarily the right thing to do --- if the604  // class is a complete object, but it's only properly aligned for a605  // base subobject, then the alignments of things relative to it are606  // probably off as well.  (Note that this requires the alignment of607  // the target to be greater than the NV alignment of the derived608  // class.)609  //610  // However, our approach to this kind of under-alignment can only611  // ever be best effort; after all, we're never going to propagate612  // alignments through variables or parameters.  Note, in particular,613  // that constructing a polymorphic type in an address that's less614  // than pointer-aligned will generally trap in the constructor,615  // unless we someday add some sort of attribute to change the616  // assumed alignment of 'this'.  So our goal here is pretty much617  // just to allow the user to explicitly say that a pointer is618  // under-aligned and then safely access its fields and vtables.619  if (actualBaseAlign >= expectedBaseAlign)620    return expectedTargetAlign;621 622  // Otherwise, we might be offset by an arbitrary multiple of the623  // actual alignment.  The correct adjustment is to take the min of624  // the two alignments.625  return std::min(actualBaseAlign, expectedTargetAlign);626}627 628/// Return the best known alignment for a pointer to a virtual base,629/// given the alignment of a pointer to the derived class.630clang::CharUnits631CIRGenModule::getVBaseAlignment(CharUnits actualDerivedAlign,632                                const CXXRecordDecl *derivedClass,633                                const CXXRecordDecl *vbaseClass) {634  // The basic idea here is that an underaligned derived pointer might635  // indicate an underaligned base pointer.636 637  assert(vbaseClass->isCompleteDefinition());638  const ASTRecordLayout &baseLayout =639      getASTContext().getASTRecordLayout(vbaseClass);640  CharUnits expectedVBaseAlign = baseLayout.getNonVirtualAlignment();641 642  return getDynamicOffsetAlignment(actualDerivedAlign, derivedClass,643                                   expectedVBaseAlign);644}645 646/// Emit a loop to call a particular constructor for each of several members647/// of an array.648///649/// \param ctor the constructor to call for each element650/// \param arrayType the type of the array to initialize651/// \param arrayBegin an arrayType*652/// \param zeroInitialize true if each element should be653///   zero-initialized before it is constructed654void CIRGenFunction::emitCXXAggrConstructorCall(655    const CXXConstructorDecl *ctor, const clang::ArrayType *arrayType,656    Address arrayBegin, const CXXConstructExpr *e, bool newPointerIsChecked,657    bool zeroInitialize) {658  QualType elementType;659  mlir::Value numElements = emitArrayLength(arrayType, elementType, arrayBegin);660  emitCXXAggrConstructorCall(ctor, numElements, arrayBegin, e,661                             newPointerIsChecked, zeroInitialize);662}663 664/// Emit a loop to call a particular constructor for each of several members665/// of an array.666///667/// \param ctor the constructor to call for each element668/// \param numElements the number of elements in the array;669///   may be zero670/// \param arrayBase a T*, where T is the type constructed by ctor671/// \param zeroInitialize true if each element should be672///   zero-initialized before it is constructed673void CIRGenFunction::emitCXXAggrConstructorCall(674    const CXXConstructorDecl *ctor, mlir::Value numElements, Address arrayBase,675    const CXXConstructExpr *e, bool newPointerIsChecked, bool zeroInitialize) {676  // It's legal for numElements to be zero.  This can happen both677  // dynamically, because x can be zero in 'new A[x]', and statically,678  // because of GCC extensions that permit zero-length arrays.  There679  // are probably legitimate places where we could assume that this680  // doesn't happen, but it's not clear that it's worth it.681 682  auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType());683  mlir::Type elementType = arrayTy.getElementType();684 685  // This might be a multi-dimensional array. Find the innermost element type.686  while (auto maybeArrayTy = mlir::dyn_cast<cir::ArrayType>(elementType))687    elementType = maybeArrayTy.getElementType();688  cir::PointerType ptrToElmType = builder.getPointerTo(elementType);689 690  // Optimize for a constant count.691  if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {692    if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) {693      // Just skip out if the constant count is zero.694      if (constIntAttr.getUInt() == 0)695        return;696 697      arrayTy = cir::ArrayType::get(elementType, constIntAttr.getUInt());698      // Otherwise, emit the check.699    }700 701    if (constantCount.use_empty())702      constantCount.erase();703  } else {704    // Otherwise, emit the check.705    cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression");706  }707 708  // Tradional LLVM codegen emits a loop here. CIR lowers to a loop as part of709  // LoweringPrepare.710 711  // The alignment of the base, adjusted by the size of a single element,712  // provides a conservative estimate of the alignment of every element.713  // (This assumes we never start tracking offsetted alignments.)714  //715  // Note that these are complete objects and so we don't need to716  // use the non-virtual size or alignment.717  CanQualType type = getContext().getCanonicalTagType(ctor->getParent());718  CharUnits eltAlignment = arrayBase.getAlignment().alignmentOfArrayElement(719      getContext().getTypeSizeInChars(type));720 721  // Zero initialize the storage, if requested.722  if (zeroInitialize)723    emitNullInitialization(*currSrcLoc, arrayBase, type);724 725  // C++ [class.temporary]p4:726  // There are two contexts in which temporaries are destroyed at a different727  // point than the end of the full-expression. The first context is when a728  // default constructor is called to initialize an element of an array.729  // If the constructor has one or more default arguments, the destruction of730  // every temporary created in a default argument expression is sequenced731  // before the construction of the next array element, if any.732  {733    RunCleanupsScope scope(*this);734 735    // Evaluate the constructor and its arguments in a regular736    // partial-destroy cleanup.737    if (getLangOpts().Exceptions &&738        !ctor->getParent()->hasTrivialDestructor()) {739      cgm.errorNYI(e->getSourceRange(), "partial array cleanups");740    }741 742    // Emit the constructor call that will execute for every array element.743    mlir::Value arrayOp =744        builder.createPtrBitcast(arrayBase.getPointer(), arrayTy);745    cir::ArrayCtor::create(746        builder, *currSrcLoc, arrayOp,747        [&](mlir::OpBuilder &b, mlir::Location loc) {748          mlir::BlockArgument arg =749              b.getInsertionBlock()->addArgument(ptrToElmType, loc);750          Address curAddr = Address(arg, elementType, eltAlignment);751          assert(!cir::MissingFeatures::sanitizers());752          auto currAVS = AggValueSlot::forAddr(753              curAddr, type.getQualifiers(), AggValueSlot::IsDestructed,754              AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap,755              AggValueSlot::IsNotZeroed);756          emitCXXConstructorCall(ctor, Ctor_Complete,757                                 /*ForVirtualBase=*/false,758                                 /*Delegating=*/false, currAVS, e);759          cir::YieldOp::create(builder, loc);760        });761  }762}763 764void CIRGenFunction::emitDelegateCXXConstructorCall(765    const CXXConstructorDecl *ctor, CXXCtorType ctorType,766    const FunctionArgList &args, SourceLocation loc) {767  CallArgList delegateArgs;768 769  FunctionArgList::const_iterator i = args.begin(), e = args.end();770  assert(i != e && "no parameters to constructor");771 772  // this773  Address thisAddr = loadCXXThisAddress();774  delegateArgs.add(RValue::get(thisAddr.getPointer()), (*i)->getType());775  ++i;776 777  // FIXME: The location of the VTT parameter in the parameter list is specific778  // to the Itanium ABI and shouldn't be hardcoded here.779  if (cgm.getCXXABI().needsVTTParameter(curGD)) {780    cgm.errorNYI(loc, "emitDelegateCXXConstructorCall: VTT parameter");781    return;782  }783 784  // Explicit arguments.785  for (; i != e; ++i) {786    const VarDecl *param = *i;787    // FIXME: per-argument source location788    emitDelegateCallArg(delegateArgs, param, loc);789  }790 791  assert(!cir::MissingFeatures::sanitizers());792 793  emitCXXConstructorCall(ctor, ctorType, /*ForVirtualBase=*/false,794                         /*Delegating=*/true, thisAddr, delegateArgs, loc);795}796 797void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) {798  const auto *assignOp = cast<CXXMethodDecl>(curGD.getDecl());799  assert(assignOp->isCopyAssignmentOperator() ||800         assignOp->isMoveAssignmentOperator());801  const Stmt *rootS = assignOp->getBody();802  assert(isa<CompoundStmt>(rootS) &&803         "Body of an implicit assignment operator should be compound stmt.");804  const auto *rootCS = cast<CompoundStmt>(rootS);805 806  cgm.setCXXSpecialMemberAttr(cast<cir::FuncOp>(curFn), assignOp);807 808  assert(!cir::MissingFeatures::incrementProfileCounter());809  assert(!cir::MissingFeatures::runCleanupsScope());810 811  // Classic codegen uses a special class to attempt to replace member812  // initializers with memcpy. We could possibly defer that to the813  // lowering or optimization phases to keep the memory accesses more814  // explicit. For now, we don't insert memcpy at all, though in some815  // cases the AST contains a call to memcpy.816  assert(!cir::MissingFeatures::assignMemcpyizer());817  for (Stmt *s : rootCS->body())818    if (emitStmt(s, /*useCurrentScope=*/true).failed())819      cgm.errorNYI(s->getSourceRange(),820                   std::string("emitImplicitAssignmentOperatorBody: ") +821                       s->getStmtClassName());822}823 824void CIRGenFunction::emitForwardingCallToLambda(825    const CXXMethodDecl *callOperator, CallArgList &callArgs) {826  // Get the address of the call operator.827  const CIRGenFunctionInfo &calleeFnInfo =828      cgm.getTypes().arrangeCXXMethodDeclaration(callOperator);829  cir::FuncOp calleePtr = cgm.getAddrOfFunction(830      GlobalDecl(callOperator), cgm.getTypes().getFunctionType(calleeFnInfo));831 832  // Prepare the return slot.833  const FunctionProtoType *fpt =834      callOperator->getType()->castAs<FunctionProtoType>();835  QualType resultType = fpt->getReturnType();836  ReturnValueSlot returnSlot;837 838  // We don't need to separately arrange the call arguments because839  // the call can't be variadic anyway --- it's impossible to forward840  // variadic arguments.841 842  // Now emit our call.843  CIRGenCallee callee =844      CIRGenCallee::forDirect(calleePtr, GlobalDecl(callOperator));845  RValue rv = emitCall(calleeFnInfo, callee, returnSlot, callArgs);846 847  // If necessary, copy the returned value into the slot.848  if (!resultType->isVoidType() && returnSlot.isNull()) {849    if (getLangOpts().ObjCAutoRefCount && resultType->isObjCRetainableType())850      cgm.errorNYI(callOperator->getSourceRange(),851                   "emitForwardingCallToLambda: ObjCAutoRefCount");852    emitReturnOfRValue(*currSrcLoc, rv, resultType);853  } else {854    cgm.errorNYI(callOperator->getSourceRange(),855                 "emitForwardingCallToLambda: return slot is not null");856  }857}858 859void CIRGenFunction::emitLambdaDelegatingInvokeBody(const CXXMethodDecl *md) {860  const CXXRecordDecl *lambda = md->getParent();861 862  // Start building arguments for forwarding call863  CallArgList callArgs;864 865  QualType lambdaType = getContext().getCanonicalTagType(lambda);866  QualType thisType = getContext().getPointerType(lambdaType);867  Address thisPtr =868      createMemTemp(lambdaType, getLoc(md->getSourceRange()), "unused.capture");869  callArgs.add(RValue::get(thisPtr.getPointer()), thisType);870 871  // Add the rest of the parameters.872  for (auto *param : md->parameters())873    emitDelegateCallArg(callArgs, param, param->getBeginLoc());874 875  const CXXMethodDecl *callOp = lambda->getLambdaCallOperator();876  // For a generic lambda, find the corresponding call operator specialization877  // to which the call to the static-invoker shall be forwarded.878  if (lambda->isGenericLambda()) {879    assert(md->isFunctionTemplateSpecialization());880    const TemplateArgumentList *tal = md->getTemplateSpecializationArgs();881    FunctionTemplateDecl *callOpTemplate =882        callOp->getDescribedFunctionTemplate();883    void *InsertPos = nullptr;884    FunctionDecl *correspondingCallOpSpecialization =885        callOpTemplate->findSpecialization(tal->asArray(), InsertPos);886    assert(correspondingCallOpSpecialization);887    callOp = cast<CXXMethodDecl>(correspondingCallOpSpecialization);888  }889  emitForwardingCallToLambda(callOp, callArgs);890}891 892void CIRGenFunction::emitLambdaStaticInvokeBody(const CXXMethodDecl *md) {893  if (md->isVariadic()) {894    // Codgen for LLVM doesn't emit code for this as well, it says:895    // FIXME: Making this work correctly is nasty because it requires either896    // cloning the body of the call operator or making the call operator897    // forward.898    cgm.errorNYI(md->getSourceRange(), "emitLambdaStaticInvokeBody: variadic");899  }900 901  emitLambdaDelegatingInvokeBody(md);902}903 904void CIRGenFunction::destroyCXXObject(CIRGenFunction &cgf, Address addr,905                                      QualType type) {906  const auto *record = type->castAsCXXRecordDecl();907  const CXXDestructorDecl *dtor = record->getDestructor();908  // TODO(cir): Unlike traditional codegen, CIRGen should actually emit trivial909  // dtors which shall be removed on later CIR passes. However, only remove this910  // assertion after we have a test case to exercise this path.911  assert(!dtor->isTrivial());912  cgf.emitCXXDestructorCall(dtor, Dtor_Complete, /*forVirtualBase*/ false,913                            /*delegating=*/false, addr, type);914}915 916namespace {917mlir::Value loadThisForDtorDelete(CIRGenFunction &cgf,918                                  const CXXDestructorDecl *dd) {919  if (Expr *thisArg = dd->getOperatorDeleteThisArg())920    return cgf.emitScalarExpr(thisArg);921  return cgf.loadCXXThis();922}923 924/// Call the operator delete associated with the current destructor.925struct CallDtorDelete final : EHScopeStack::Cleanup {926  CallDtorDelete() {}927 928  void emit(CIRGenFunction &cgf) override {929    const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(cgf.curFuncDecl);930    const CXXRecordDecl *classDecl = dtor->getParent();931    cgf.emitDeleteCall(dtor->getOperatorDelete(),932                       loadThisForDtorDelete(cgf, dtor),933                       cgf.getContext().getCanonicalTagType(classDecl));934  }935};936 937class DestroyField final : public EHScopeStack::Cleanup {938  const FieldDecl *field;939  CIRGenFunction::Destroyer *destroyer;940 941public:942  DestroyField(const FieldDecl *field, CIRGenFunction::Destroyer *destroyer)943      : field(field), destroyer(destroyer) {}944 945  void emit(CIRGenFunction &cgf) override {946    // Find the address of the field.947    Address thisValue = cgf.loadCXXThisAddress();948    CanQualType recordTy =949        cgf.getContext().getCanonicalTagType(field->getParent());950    LValue thisLV = cgf.makeAddrLValue(thisValue, recordTy);951    LValue lv = cgf.emitLValueForField(thisLV, field);952    assert(lv.isSimple());953 954    assert(!cir::MissingFeatures::ehCleanupFlags());955    cgf.emitDestroy(lv.getAddress(), field->getType(), destroyer);956  }957};958} // namespace959 960/// Emit all code that comes at the end of class's destructor. This is to call961/// destructors on members and base classes in reverse order of their962/// construction.963///964/// For a deleting destructor, this also handles the case where a destroying965/// operator delete completely overrides the definition.966void CIRGenFunction::enterDtorCleanups(const CXXDestructorDecl *dd,967                                       CXXDtorType dtorType) {968  assert((!dd->isTrivial() || dd->hasAttr<DLLExportAttr>()) &&969         "Should not emit dtor epilogue for non-exported trivial dtor!");970 971  // The deleting-destructor phase just needs to call the appropriate972  // operator delete that Sema picked up.973  if (dtorType == Dtor_Deleting) {974    assert(dd->getOperatorDelete() &&975           "operator delete missing - EnterDtorCleanups");976    if (cxxStructorImplicitParamValue) {977      cgm.errorNYI(dd->getSourceRange(), "deleting destructor with vtt");978    } else {979      if (dd->getOperatorDelete()->isDestroyingOperatorDelete()) {980        cgm.errorNYI(dd->getSourceRange(),981                     "deleting destructor with destroying operator delete");982      } else {983        ehStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);984      }985    }986    return;987  }988 989  const CXXRecordDecl *classDecl = dd->getParent();990 991  // Unions have no bases and do not call field destructors.992  if (classDecl->isUnion())993    return;994 995  // The complete-destructor phase just destructs all the virtual bases.996  if (dtorType == Dtor_Complete) {997    assert(!cir::MissingFeatures::sanitizers());998 999    // We push them in the forward order so that they'll be popped in1000    // the reverse order.1001    for (const CXXBaseSpecifier &base : classDecl->vbases()) {1002      auto *baseClassDecl = base.getType()->castAsCXXRecordDecl();1003 1004      if (baseClassDecl->hasTrivialDestructor()) {1005        // Under SanitizeMemoryUseAfterDtor, poison the trivial base class1006        // memory. For non-trival base classes the same is done in the class1007        // destructor.1008        assert(!cir::MissingFeatures::sanitizers());1009      } else {1010        ehStack.pushCleanup<CallBaseDtor>(NormalAndEHCleanup, baseClassDecl,1011                                          /*baseIsVirtual=*/true);1012      }1013    }1014 1015    return;1016  }1017 1018  assert(dtorType == Dtor_Base);1019  assert(!cir::MissingFeatures::sanitizers());1020 1021  // Destroy non-virtual bases.1022  for (const CXXBaseSpecifier &base : classDecl->bases()) {1023    // Ignore virtual bases.1024    if (base.isVirtual())1025      continue;1026 1027    CXXRecordDecl *baseClassDecl = base.getType()->getAsCXXRecordDecl();1028 1029    if (baseClassDecl->hasTrivialDestructor())1030      assert(!cir::MissingFeatures::sanitizers());1031    else1032      ehStack.pushCleanup<CallBaseDtor>(NormalAndEHCleanup, baseClassDecl,1033                                        /*baseIsVirtual=*/false);1034  }1035 1036  assert(!cir::MissingFeatures::sanitizers());1037 1038  // Destroy direct fields.1039  for (const FieldDecl *field : classDecl->fields()) {1040    QualType type = field->getType();1041    QualType::DestructionKind dtorKind = type.isDestructedType();1042    if (!dtorKind)1043      continue;1044 1045    // Anonymous union members do not have their destructors called.1046    const RecordType *rt = type->getAsUnionType();1047    if (rt && rt->getDecl()->isAnonymousStructOrUnion())1048      continue;1049 1050    CleanupKind cleanupKind = getCleanupKind(dtorKind);1051    assert(!cir::MissingFeatures::ehCleanupFlags());1052    ehStack.pushCleanup<DestroyField>(cleanupKind, field,1053                                      getDestroyer(dtorKind));1054  }1055}1056 1057void CIRGenFunction::emitDelegatingCXXConstructorCall(1058    const CXXConstructorDecl *ctor, const FunctionArgList &args) {1059  assert(ctor->isDelegatingConstructor());1060 1061  Address thisPtr = loadCXXThisAddress();1062 1063  assert(!cir::MissingFeatures::objCGC());1064  assert(!cir::MissingFeatures::sanitizers());1065  AggValueSlot aggSlot = AggValueSlot::forAddr(1066      thisPtr, Qualifiers(), AggValueSlot::IsDestructed,1067      AggValueSlot::IsNotAliased, AggValueSlot::MayOverlap,1068      AggValueSlot::IsNotZeroed);1069 1070  emitAggExpr(ctor->init_begin()[0]->getInit(), aggSlot);1071 1072  const CXXRecordDecl *classDecl = ctor->getParent();1073  if (cgm.getLangOpts().Exceptions && !classDecl->hasTrivialDestructor()) {1074    cgm.errorNYI(ctor->getSourceRange(),1075                 "emitDelegatingCXXConstructorCall: exception");1076    return;1077  }1078}1079 1080void CIRGenFunction::emitCXXDestructorCall(const CXXDestructorDecl *dd,1081                                           CXXDtorType type,1082                                           bool forVirtualBase, bool delegating,1083                                           Address thisAddr, QualType thisTy) {1084  cgm.getCXXABI().emitDestructorCall(*this, dd, type, forVirtualBase,1085                                     delegating, thisAddr, thisTy);1086}1087 1088mlir::Value CIRGenFunction::getVTTParameter(GlobalDecl gd, bool forVirtualBase,1089                                            bool delegating) {1090  if (!cgm.getCXXABI().needsVTTParameter(gd))1091    return nullptr;1092 1093  const CXXRecordDecl *rd = cast<CXXMethodDecl>(curCodeDecl)->getParent();1094  const CXXRecordDecl *base = cast<CXXMethodDecl>(gd.getDecl())->getParent();1095 1096  uint64_t subVTTIndex;1097 1098  if (delegating) {1099    // If this is a delegating constructor call, just load the VTT.1100    return loadCXXVTT();1101  } else if (rd == base) {1102    // If the record matches the base, this is the complete ctor/dtor1103    // variant calling the base variant in a class with virtual bases.1104    assert(!cgm.getCXXABI().needsVTTParameter(curGD) &&1105           "doing no-op VTT offset in base dtor/ctor?");1106    assert(!forVirtualBase && "Can't have same class as virtual base!");1107    subVTTIndex = 0;1108  } else {1109    const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd);1110    CharUnits baseOffset = forVirtualBase ? layout.getVBaseClassOffset(base)1111                                          : layout.getBaseClassOffset(base);1112 1113    subVTTIndex =1114        cgm.getVTables().getSubVTTIndex(rd, BaseSubobject(base, baseOffset));1115    assert(subVTTIndex != 0 && "Sub-VTT index must be greater than zero!");1116  }1117 1118  mlir::Location loc = cgm.getLoc(rd->getBeginLoc());1119  if (cgm.getCXXABI().needsVTTParameter(curGD)) {1120    // A VTT parameter was passed to the constructor, use it.1121    mlir::Value vtt = loadCXXVTT();1122    return builder.createVTTAddrPoint(loc, vtt.getType(), vtt, subVTTIndex);1123  } else {1124    // We're the complete constructor, so get the VTT by name.1125    cir::GlobalOp vtt = cgm.getVTables().getAddrOfVTT(rd);1126    return builder.createVTTAddrPoint(1127        loc, builder.getPointerTo(cgm.voidPtrTy),1128        mlir::FlatSymbolRefAttr::get(vtt.getSymNameAttr()), subVTTIndex);1129  }1130}1131 1132Address CIRGenFunction::getAddressOfDerivedClass(1133    mlir::Location loc, Address baseAddr, const CXXRecordDecl *derived,1134    llvm::iterator_range<CastExpr::path_const_iterator> path,1135    bool nullCheckValue) {1136  assert(!path.empty() && "Base path should not be empty!");1137 1138  QualType derivedTy = getContext().getCanonicalTagType(derived);1139  mlir::Type derivedValueTy = convertType(derivedTy);1140  CharUnits nonVirtualOffset =1141      cgm.computeNonVirtualBaseClassOffset(derived, path);1142 1143  // Note that in OG, no offset (nonVirtualOffset.getQuantity() == 0) means it1144  // just gives the address back. In CIR a `cir.derived_class` is created and1145  // made into a nop later on during lowering.1146  return builder.createDerivedClassAddr(loc, baseAddr, derivedValueTy,1147                                        nonVirtualOffset.getQuantity(),1148                                        /*assumeNotNull=*/!nullCheckValue);1149}1150 1151Address CIRGenFunction::getAddressOfBaseClass(1152    Address value, const CXXRecordDecl *derived,1153    llvm::iterator_range<CastExpr::path_const_iterator> path,1154    bool nullCheckValue, SourceLocation loc) {1155  assert(!path.empty() && "Base path should not be empty!");1156 1157  CastExpr::path_const_iterator start = path.begin();1158  const CXXRecordDecl *vBase = nullptr;1159 1160  if ((*path.begin())->isVirtual()) {1161    vBase = (*start)->getType()->castAsCXXRecordDecl();1162    ++start;1163  }1164 1165  // Compute the static offset of the ultimate destination within its1166  // allocating subobject (the virtual base, if there is one, or else1167  // the "complete" object that we see).1168  CharUnits nonVirtualOffset = cgm.computeNonVirtualBaseClassOffset(1169      vBase ? vBase : derived, {start, path.end()});1170 1171  // If there's a virtual step, we can sometimes "devirtualize" it.1172  // For now, that's limited to when the derived type is final.1173  // TODO: "devirtualize" this for accesses to known-complete objects.1174  if (vBase && derived->hasAttr<FinalAttr>()) {1175    const ASTRecordLayout &layout = getContext().getASTRecordLayout(derived);1176    CharUnits vBaseOffset = layout.getVBaseClassOffset(vBase);1177    nonVirtualOffset += vBaseOffset;1178    vBase = nullptr; // we no longer have a virtual step1179  }1180 1181  // Get the base pointer type.1182  mlir::Type baseValueTy = convertType((path.end()[-1])->getType());1183  assert(!cir::MissingFeatures::addressSpace());1184 1185  // If there is no virtual base, use cir.base_class_addr.  It takes care of1186  // the adjustment and the null pointer check.1187  if (nonVirtualOffset.isZero() && !vBase) {1188    assert(!cir::MissingFeatures::sanitizers());1189    return builder.createBaseClassAddr(getLoc(loc), value, baseValueTy, 0,1190                                       /*assumeNotNull=*/true);1191  }1192 1193  assert(!cir::MissingFeatures::sanitizers());1194 1195  // Compute the virtual offset.1196  mlir::Value virtualOffset = nullptr;1197  if (vBase) {1198    virtualOffset = cgm.getCXXABI().getVirtualBaseClassOffset(1199        getLoc(loc), *this, value, derived, vBase);1200  }1201 1202  // Apply both offsets.1203  value = applyNonVirtualAndVirtualOffset(1204      getLoc(loc), *this, value, nonVirtualOffset, virtualOffset, derived,1205      vBase, baseValueTy, not nullCheckValue);1206 1207  // Cast to the destination type.1208  value = value.withElementType(builder, baseValueTy);1209 1210  return value;1211}1212 1213// TODO(cir): this can be shared with LLVM codegen.1214bool CIRGenFunction::shouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *rd) {1215  assert(!cir::MissingFeatures::hiddenVisibility());1216  if (!cgm.getCodeGenOpts().WholeProgramVTables)1217    return false;1218 1219  if (cgm.getCodeGenOpts().VirtualFunctionElimination)1220    return true;1221 1222  assert(!cir::MissingFeatures::sanitizers());1223 1224  return false;1225}1226 1227mlir::Value CIRGenFunction::getVTablePtr(mlir::Location loc, Address thisAddr,1228                                         const CXXRecordDecl *rd) {1229  auto vtablePtr = cir::VTableGetVPtrOp::create(1230      builder, loc, builder.getPtrToVPtrType(), thisAddr.getPointer());1231  Address vtablePtrAddr = Address(vtablePtr, thisAddr.getAlignment());1232 1233  auto vtable = builder.createLoad(loc, vtablePtrAddr);1234  assert(!cir::MissingFeatures::opTBAA());1235 1236  if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&1237      cgm.getCodeGenOpts().StrictVTablePointers) {1238    assert(!cir::MissingFeatures::createInvariantGroup());1239  }1240 1241  return vtable;1242}1243 1244void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d,1245                                            clang::CXXCtorType type,1246                                            bool forVirtualBase,1247                                            bool delegating,1248                                            AggValueSlot thisAVS,1249                                            const clang::CXXConstructExpr *e) {1250  CallArgList args;1251  Address thisAddr = thisAVS.getAddress();1252  QualType thisType = d->getThisType();1253  mlir::Value thisPtr = thisAddr.getPointer();1254 1255  assert(!cir::MissingFeatures::addressSpace());1256 1257  args.add(RValue::get(thisPtr), thisType);1258 1259  // In LLVM Codegen: If this is a trivial constructor, just emit what's needed.1260  // If this is a union copy constructor, we must emit a memcpy, because the AST1261  // does not model that copy.1262  assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember());1263 1264  const FunctionProtoType *fpt = d->getType()->castAs<FunctionProtoType>();1265 1266  assert(!cir::MissingFeatures::opCallArgEvaluationOrder());1267 1268  emitCallArgs(args, fpt, e->arguments(), e->getConstructor(),1269               /*ParamsToSkip=*/0);1270 1271  assert(!cir::MissingFeatures::sanitizers());1272  emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args,1273                         e->getExprLoc());1274}1275 1276void CIRGenFunction::emitCXXConstructorCall(1277    const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase,1278    bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) {1279 1280  const CXXRecordDecl *crd = d->getParent();1281 1282  // If this is a call to a trivial default constructor:1283  // In LLVM: do nothing.1284  // In CIR: emit as a regular call, other later passes should lower the1285  // ctor call into trivial initialization.1286  assert(!cir::MissingFeatures::isTrivialCtorOrDtor());1287 1288  assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember());1289 1290  bool passPrototypeArgs = true;1291 1292  // Check whether we can actually emit the constructor before trying to do so.1293  if (d->getInheritedConstructor()) {1294    cgm.errorNYI(d->getSourceRange(),1295                 "emitCXXConstructorCall: inherited constructor");1296    return;1297  }1298 1299  // Insert any ABI-specific implicit constructor arguments.1300  CIRGenCXXABI::AddedStructorArgCounts extraArgs =1301      cgm.getCXXABI().addImplicitConstructorArgs(*this, d, type, forVirtualBase,1302                                                 delegating, args);1303 1304  // Emit the call.1305  auto calleePtr = cgm.getAddrOfCXXStructor(GlobalDecl(d, type));1306  const CIRGenFunctionInfo &info = cgm.getTypes().arrangeCXXConstructorCall(1307      args, d, type, extraArgs.prefix, extraArgs.suffix, passPrototypeArgs);1308  CIRGenCallee callee = CIRGenCallee::forDirect(calleePtr, GlobalDecl(d, type));1309  cir::CIRCallOpInterface c;1310  emitCall(info, callee, ReturnValueSlot(), args, &c, getLoc(loc));1311 1312  if (cgm.getCodeGenOpts().OptimizationLevel != 0 && !crd->isDynamicClass() &&1313      type != Ctor_Base && cgm.getCodeGenOpts().StrictVTablePointers)1314    cgm.errorNYI(d->getSourceRange(), "vtable assumption loads");1315}1316