[clang] [CIR] Add initial Microsoft C++ ABI support in ClangIR (PR #233291)

Kazu Hirata via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 18 14:21:21 PDT 2026


================
@@ -114,210 +241,878 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI {
   }
 
   const CXXRecordDecl *
-  getThisArgumentTypeForMethod(const CXXMethodDecl *md) override {
-    cgm.errorNYI(md->getSourceRange(),
-                 "getThisArgumentTypeForMethod: MSVC ABI");
-    return md->getParent();
-  }
+  getThisArgumentTypeForMethod(const CXXMethodDecl *md) override;
 
   Address adjustThisArgumentForVirtualFunctionCall(CIRGenFunction &cgf,
                                                    GlobalDecl gd,
-                                                   Address thisAddr,
-                                                   bool virtualCall) override {
-    cgf.cgm.errorNYI(gd.getDecl()->getSourceRange(),
-                     "adjustThisArgumentForVirtualFunctionCall: MSVC ABI");
-    return thisAddr;
-  }
+                                                   Address thisPtr,
+                                                   bool virtualCall) override;
 
   bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
                                            CIRGenFunction::VPtr vptr) override {
-    cgf.cgm.errorNYI("isVirtualOffsetNeededForVTableField: MSVC ABI");
-    return false;
+    return vptr.nearestVBase != nullptr;
   }
 
   cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,
-                                CharUnits vptrOffset) override {
-    cgm.errorNYI(rd->getSourceRange(), "getAddrOfVTable: MSVC ABI");
-    return nullptr;
-  }
+                                CharUnits vptrOffset) override;
 
   mlir::Value getVTableAddressPoint(BaseSubobject base,
-                                    const CXXRecordDecl *vtableClass) override {
-    cgm.errorNYI(vtableClass->getSourceRange(),
-                 "getVTableAddressPoint: MSVC ABI");
-    return nullptr;
-  }
+                                    const CXXRecordDecl *vtableClass) override;
 
   mlir::Value getVTableAddressPointInStructor(
       CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
-      const CXXRecordDecl *nearestVBase) override {
-    cgf.cgm.errorNYI(vtableClass->getSourceRange(),
-                     "getVTableAddressPointInStructor: MSVC ABI");
-    return nullptr;
-  }
+      const CXXRecordDecl *nearestVBase) override;
 
   CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf, GlobalDecl gd,
                                          Address thisAddr, mlir::Type ty,
-                                         SourceLocation loc) override {
-    cgf.cgm.errorNYI(loc, "getVirtualFunctionPointer: MSVC ABI");
-    return CIRGenCallee();
-  }
+                                         SourceLocation loc) override;
 
   void emitVTableDefinitions(CIRGenVTables &cgvt,
-                             const CXXRecordDecl *rd) override {
-    cgm.errorNYI(rd->getSourceRange(), "emitVTableDefinitions: MSVC ABI");
-  }
+                             const CXXRecordDecl *rd) override;
 
-  void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override {
-    cgm.errorNYI(rd->getSourceRange(),
-                 "emitVirtualInheritanceTables: MSVC ABI");
-  }
+  void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
 
   void
   initializeHiddenVirtualInheritanceMembers(CIRGenFunction &cgf,
-                                            const CXXRecordDecl *rd) override {
-    cgf.cgm.errorNYI(rd->getSourceRange(),
-                     "initializeHiddenVirtualInheritanceMembers: MSVC ABI");
-  }
+                                            const CXXRecordDecl *rd) override;
 
   mlir::Value
   getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
                             Address thisAddr, const CXXRecordDecl *classDecl,
-                            const CXXRecordDecl *baseClassDecl) override {
-    cgf.cgm.errorNYI(loc, "getVirtualBaseClassOffset: MSVC ABI");
-    return nullptr;
-  }
+                            const CXXRecordDecl *baseClassDecl) override;
 
   cir::MethodAttr buildVirtualMethodAttr(cir::MethodType methodTy,
-                                         const CXXMethodDecl *md) override {
-    cgm.errorNYI(md->getSourceRange(), "buildVirtualMethodAttr: MSVC ABI");
-    return cir::MethodAttr();
-  }
+                                         const CXXMethodDecl *md) override;
 
   mlir::Value performThisAdjustment(CIRGenFunction &cgf, Address thisAddr,
                                     const CXXRecordDecl *unadjustedClass,
-                                    const ThunkInfo &ti) override {
-    cgf.cgm.errorNYI("performThisAdjustment: MSVC ABI");
-    return thisAddr.emitRawPointer();
-  }
+                                    const ThunkInfo &ti) override;
 
   mlir::Value performReturnAdjustment(CIRGenFunction &cgf, Address ret,
                                       const CXXRecordDecl *unadjustedClass,
-                                      const ReturnAdjustment &ra) override {
-    cgf.cgm.errorNYI("performReturnAdjustment: MSVC ABI");
-    return ret.emitRawPointer();
+                                      const ReturnAdjustment &ra) override;
+
+  bool shouldTypeidBeNullChecked(QualType srcTy) override;
+  mlir::Value emitTypeid(CIRGenFunction &cgf, QualType srcTy, Address thisPtr,
+                         mlir::Type typeInfoPtrTy) override;
+  void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override;
+  void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override;
+
+  mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc,
+                              QualType srcRecordTy, QualType destRecordTy,
+                              cir::PointerType destCIRTy, bool isRefCast,
+                              Address src) override;
+
+  mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+                                          QualType ty) override;
+  CatchTypeInfo
+  getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
+                               QualType catchHandlerType) override;
+
+  void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
+  void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
+  void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
+                          mlir::Value addr) override;
+};
+
+} // namespace
+
+CharUnits
+CIRGenMicrosoftCXXABI::getVirtualFunctionPrologueThisAdjustment(GlobalDecl gd) {
+  const auto *md = cast<CXXMethodDecl>(gd.getDecl());
+
+  if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
+    if (gd.getDtorType() == Dtor_Complete)
+      return CharUnits();
+
+    gd = GlobalDecl(dd,
+                    cgm.getASTContext().getTargetInfo().emitVectorDeletingDtors(
+                        cgm.getASTContext().getLangOpts())
+                        ? Dtor_VectorDeleting
+                        : Dtor_Deleting);
   }
 
-  bool canSpeculativelyEmitVTable(const CXXRecordDecl *rd) const override {
-    return false;
+  MethodVFTableLocation ml =
+      cgm.getMicrosoftVTableContext().getMethodVFTableLocation(gd);
+  CharUnits adjustment = ml.VFPtrOffset;
+
+  if (isa<CXXDestructorDecl>(md))
+    adjustment = CharUnits::Zero();
+
+  if (ml.VBase) {
+    const ASTRecordLayout &derivedLayout =
+        cgm.getASTContext().getASTRecordLayout(md->getParent());
+    adjustment += derivedLayout.getVBaseClassOffset(ml.VBase);
   }
 
-  bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
-    cgm.errorNYI(vtableClass->getSourceRange(),
-                 "doStructorsInitializeVPtrs: MSVC ABI");
-    return false;
+  return adjustment;
+}
+
+mlir::Value CIRGenMicrosoftCXXABI::getVBaseOffsetFromVBPtr(
+    CIRGenFunction &cgf, mlir::Location loc, Address thisAddr,
+    int64_t vbPtrOffset, unsigned vbTableIndex, mlir::Value *vbPtrOut) {
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  cir::PointerType u8PtrTy = builder.getUInt8PtrTy();
+  mlir::Value thisBytePtr =
+      builder.createBitcast(thisAddr.getPointer(), u8PtrTy);
+
+  mlir::Value vbPtrOffsetVal = builder.getSInt32(vbPtrOffset, loc);
+  mlir::Value vbPtr = cir::PtrStrideOp::create(builder, loc, u8PtrTy,
+                                               thisBytePtr, vbPtrOffsetVal);
+  if (vbPtrOut)
+    *vbPtrOut = vbPtr;
+
+  CharUnits vbPtrAlign = cgf.getPointerAlign();
+  Address vbPtrAddr(builder.createBitcast(vbPtr, builder.getPointerTo(u8PtrTy)),
+                    u8PtrTy, vbPtrAlign);
+  mlir::Value vbTable = builder.createLoad(loc, vbPtrAddr);
+
+  mlir::Type i32Ty = builder.getSInt32Ty();
+  cir::PointerType i32PtrTy = builder.getPointerTo(i32Ty);
+  mlir::Value vbTableI32Ptr = builder.createBitcast(vbTable, i32PtrTy);
+  mlir::Value vbTableIndexVal = builder.getSInt32(vbTableIndex, loc);
+  mlir::Value vbaseOffsPtr = cir::PtrStrideOp::create(
+      builder, loc, i32PtrTy, vbTableI32Ptr, vbTableIndexVal);
+  Address vbaseOffsAddr(vbaseOffsPtr, i32Ty, CharUnits::fromQuantity(4));
+  return builder.createLoad(loc, vbaseOffsAddr);
+}
+
+Address CIRGenMicrosoftCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
+                                                     Address newPtr,
+                                                     mlir::Value numElements,
+                                                     const CXXNewExpr *e,
+                                                     QualType elementType) {
+  assert(requiresArrayCookie(e));
+  CharUnits cookieSize = getArrayCookieSizeImpl(elementType);
+  mlir::Location loc = cgf.getLoc(e->getSourceRange());
+
+  mlir::Type u8Ty = cgf.getBuilder().getUInt8Ty();
+  cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
+  mlir::Value baseBytePtr =
+      cgf.getBuilder().createBitcast(newPtr.getPointer(), u8PtrTy);
+
+  // In the MSVC ABI, the cookie is located at offset 0 of newPtr.
+  CharUnits baseAlignment = newPtr.getAlignment();
+  Address cookiePtr(baseBytePtr, u8Ty, baseAlignment);
+  Address numElementsPtr =
+      cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
+  cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
+
+  // Skip over the cookie to return the pointer to the element array.
+  mlir::Value dataOffset =
+      cgf.getBuilder().getSInt32(cookieSize.getQuantity(), loc);
+  mlir::Value dataPtr =
+      cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);
+  mlir::Value finalPtr =
+      cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());
+  CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
+  return Address(finalPtr, newPtr.getElementType(), finalAlignment);
+}
+
+CIRGenCXXABI::AddedStructorArgCounts
+CIRGenMicrosoftCXXABI::buildStructorSignature(
+    GlobalDecl gd, llvm::SmallVectorImpl<CanQualType> &argTys) {
+  AddedStructorArgCounts added;
+  if (isa<CXXDestructorDecl>(gd.getDecl()) &&
+      (gd.getDtorType() == Dtor_Deleting ||
+       gd.getDtorType() == Dtor_VectorDeleting)) {
+    argTys.push_back(cgm.getASTContext().IntTy);
+    ++added.suffix;
   }
+  auto *cd = dyn_cast<CXXConstructorDecl>(gd.getDecl());
+  if (!cd)
+    return added;
 
-  bool exportThunk() override { return false; }
+  const CXXRecordDecl *classDecl = cd->getParent();
+  const FunctionProtoType *fpt = cd->getType()->castAs<FunctionProtoType>();
+  if (classDecl->getNumVBases()) {
+    if (fpt->isVariadic()) {
+      argTys.insert(argTys.begin() + 1, cgm.getASTContext().IntTy);
+      ++added.prefix;
+    } else {
+      argTys.push_back(cgm.getASTContext().IntTy);
+      ++added.suffix;
+    }
+  }
 
-  bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
-                              CXXDtorType dt) const override {
-    cgm.errorNYI(dtor->getSourceRange(), "useThunkForDtorVariant: MSVC ABI");
-    return false;
+  return added;
+}
+
+void CIRGenMicrosoftCXXABI::addImplicitStructorParams(CIRGenFunction &cgf,
+                                                      QualType &resTy,
+                                                      FunctionArgList &params) {
+  ASTContext &context = cgm.getASTContext();
+  const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
+  assert(isa<CXXConstructorDecl>(md) || isa<CXXDestructorDecl>(md));
+
+  if (isa<CXXConstructorDecl>(md) && md->getParent()->getNumVBases()) {
+    auto *isMostDerived = ImplicitParamDecl::Create(
+        context, /*DC=*/nullptr, cgf.curGD.getDecl()->getLocation(),
+        &context.Idents.get("is_most_derived"), context.IntTy,
+        ImplicitParamKind::Other);
+    const FunctionProtoType *fpt = md->getType()->castAs<FunctionProtoType>();
+    if (fpt->isVariadic())
+      params.insert(params.begin() + 1, isMostDerived);
+    else
+      params.push_back(isMostDerived);
+    getStructorImplicitParamDecl(cgf) = isMostDerived;
+  } else if (isDeletingDtor(cgf.curGD)) {
+    auto *shouldDelete = ImplicitParamDecl::Create(
+        context, /*DC=*/nullptr, cgf.curGD.getDecl()->getLocation(),
+        &context.Idents.get("should_call_delete"), context.IntTy,
+        ImplicitParamKind::Other);
+    params.push_back(shouldDelete);
+    getStructorImplicitParamDecl(cgf) = shouldDelete;
   }
+}
 
-  void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd,
-                       bool returnAdjustment) override {
-    cgm.errorNYI(gd.getDecl()->getSourceRange(), "setThunkLinkage: MSVC ABI");
+void CIRGenMicrosoftCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
+                                                       CIRGenFunction &cgf) {
+  if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>())
+    return;
+
+  mlir::Value thisVal = loadIncomingCXXThis(cgf);
+  const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
+  if (!cgf.curFuncIsThunk && md->isVirtual()) {
+    CharUnits adjustment = getVirtualFunctionPrologueThisAdjustment(cgf.curGD);
+    if (!adjustment.isZero()) {
+      assert(adjustment.isPositive());
+      CIRGenBuilderTy &builder = cgf.getBuilder();
+      mlir::Location mlirLoc = cgf.getLoc(loc);
+      cir::PointerType u8PtrTy = builder.getUInt8PtrTy();
+      mlir::Value u8This = builder.createBitcast(thisVal, u8PtrTy);
+      mlir::Value negAdj =
+          builder.getSInt32(-adjustment.getQuantity(), mlirLoc);
+      mlir::Value adjusted =
+          cir::PtrStrideOp::create(builder, mlirLoc, u8PtrTy, u8This, negAdj);
+      thisVal = builder.createBitcast(adjusted, thisVal.getType());
+    }
   }
+  setCXXABIThisValue(cgf, thisVal);
 
-  StringRef getPureVirtualCallName() override { return "_purecall"; }
-  StringRef getDeletedVirtualCallName() override { return "_purecall"; }
+  if (hasThisReturn(cgf.curGD) || hasMostDerivedReturn(cgf.curGD)) {
+    if (cgf.returnValue.isValid())
+      cgf.getBuilder().createStore(cgf.getLoc(loc), thisVal, cgf.returnValue);
+  }
 
-  bool isZeroInitializable(const MemberPointerType *mpt) override {
-    cgm.errorNYI("isZeroInitializable: MSVC ABI");
-    return true;
+  if (isa<CXXConstructorDecl>(md) && md->getParent()->getNumVBases()) {
+    assert(getStructorImplicitParamDecl(cgf) &&
+           "no implicit parameter for a constructor with virtual bases?");
+    Address addr = cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf));
+    setStructorImplicitParamValue(
+        cgf, cgf.getBuilder().createLoad(cgf.getLoc(loc), addr));
   }
 
-  bool requiresArrayCookie(const CXXNewExpr *e) override {
-    cgm.errorNYI(e->getSourceRange(), "requiresArrayCookie: MSVC ABI");
-    return false;
+  if (isDeletingDtor(cgf.curGD)) {
+    assert(getStructorImplicitParamDecl(cgf) &&
+           "no implicit parameter for a deleting destructor?");
+    Address addr = cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf));
+    setStructorImplicitParamValue(
+        cgf, cgf.getBuilder().createLoad(cgf.getLoc(loc), addr));
   }
+}
 
-  CharUnits getArrayCookieSizeImpl(QualType elementType) override {
-    cgm.errorNYI("getArrayCookieSizeImpl: MSVC ABI");
-    return CharUnits::Zero();
+CIRGenCXXABI::AddedStructorArgs
+CIRGenMicrosoftCXXABI::getImplicitConstructorArgs(CIRGenFunction &cgf,
+                                                  const CXXConstructorDecl *d,
+                                                  CXXCtorType type,
+                                                  bool forVirtualBase,
+                                                  bool delegating) {
+  assert(type == Ctor_Complete || type == Ctor_Base);
+
+  if (!d->getParent()->getNumVBases())
+    return AddedStructorArgs{};
+
+  const FunctionProtoType *fpt = d->getType()->castAs<FunctionProtoType>();
+  mlir::Value mostDerivedArg;
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  mlir::Location loc = cgf.getLoc(d->getLocation());
+  if (delegating) {
+    mostDerivedArg = getStructorImplicitParamValue(cgf);
+  } else {
+    mostDerivedArg = builder.getSInt32(type == Ctor_Complete ? 1 : 0, loc);
+  }
+  if (fpt->isVariadic()) {
+    return AddedStructorArgs::withPrefix(
+        {{mostDerivedArg, cgm.getASTContext().IntTy}});
   }
+  return AddedStructorArgs::withSuffix(
+      {{mostDerivedArg, cgm.getASTContext().IntTy}});
+}
 
-  Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,
-                                mlir::Value numElements, const CXXNewExpr *e,
-                                QualType elementType) override {
-    cgf.cgm.errorNYI(e->getSourceRange(), "initializeArrayCookie: MSVC ABI");
-    return newPtr;
+void CIRGenMicrosoftCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {
+  cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));
+}
+
+void CIRGenMicrosoftCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
+  cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
+
+  if (d->getParent()->getNumVBases() > 0 && d->hasAttr<DLLExportAttr>())
+    cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
+}
+
+void CIRGenMicrosoftCXXABI::emitCXXStructor(GlobalDecl gd) {
+  if (auto *ctor = dyn_cast<CXXConstructorDecl>(gd.getDecl())) {
+    auto fn = cgm.codegenCXXStructor(gd.getWithCtorType(Ctor_Complete));
+    cgm.maybeSetTrivialComdat(*ctor, fn);
+    return;
   }
 
-  bool shouldTypeidBeNullChecked(QualType srcTy) override {
-    cgm.errorNYI("shouldTypeidBeNullChecked: MSVC ABI");
-    return false;
+  auto *dtor = cast<CXXDestructorDecl>(gd.getDecl());
+  if (gd.getDtorType() == Dtor_Complete &&
+      dtor->getParent()->getNumVBases() == 0)
+    gd = gd.getWithDtorType(Dtor_Base);
+
+  if (gd.getDtorType() == Dtor_Deleting ||
+      gd.getDtorType() == Dtor_VectorDeleting) {
+    cgm.errorNYI(dtor->getSourceRange(),
+                 "emitCXXStructor: MSVC deleting destructor");
+    return;
   }
 
-  mlir::Value emitTypeid(CIRGenFunction &cgf, QualType srcTy, Address thisPtr,
-                         mlir::Type typeInfoPtrTy) override {
-    cgf.cgm.errorNYI(cgf.getLoc(srcTy->getAsCXXRecordDecl()->getLocation()),
-                     "emitTypeid: MSVC ABI");
-    return cgf.getBuilder().getNullPtr(
-        typeInfoPtrTy, cgf.getLoc(srcTy->getAsCXXRecordDecl()->getLocation()));
+  auto fn = cgm.codegenCXXStructor(gd);
+  cgm.maybeSetTrivialComdat(*dtor, fn);
+}
+
+void CIRGenMicrosoftCXXABI::emitDestructorCall(
+    CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
+    bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
+  if (type == Dtor_Complete && dd->getParent()->getNumVBases() == 0)
+    type = Dtor_Base;
+
+  GlobalDecl gd(dd, type);
+  CIRGenCallee callee =
+      CIRGenCallee::forDirect(cgm.getAddrOfCXXStructor(gd).getOperation(), gd);
+
+  if (dd->isVirtual()) {
+    assert(type != CXXDtorType::Dtor_Deleting &&
+           "The deleting destructor should only be called via a virtual call");
+    thisAddr = adjustThisArgumentForVirtualFunctionCall(
+        cgf, GlobalDecl(dd, type), thisAddr, false);
   }
 
-  void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override {
-    cgf.cgm.errorNYI(loc, "emitBadTypeidCall: MSVC ABI");
+  cgf.emitCXXDestructorCall(gd, callee, thisAddr.emitRawPointer(), thisTy,
+                            /*implicitParam=*/nullptr,
+                            /*implicitParamTy=*/QualType(), /*e=*/nullptr);
+}
+
+mlir::Value CIRGenMicrosoftCXXABI::emitVirtualDestructorCall(
+    CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType,
+    Address thisAddr, DeleteOrMemberCallExpr e) {
+  auto *ce = dyn_cast<const CXXMemberCallExpr *>(e);
+  auto *de = dyn_cast<const CXXDeleteExpr *>(e);
+  assert((ce != nullptr) ^ (de != nullptr));
+  assert(ce == nullptr || ce->arg_begin() == ce->arg_end());
+
+  ASTContext &context = cgm.getASTContext();
+  bool vectorDeletingDtorsEnabled =
+      context.getTargetInfo().emitVectorDeletingDtors(context.getLangOpts());
+  GlobalDecl gd(dtor, vectorDeletingDtorsEnabled ? Dtor_VectorDeleting
+                                                 : Dtor_Deleting);
+  const CIRGenFunctionInfo *fInfo =
+      &cgm.getTypes().arrangeCXXStructorDeclaration(gd);
+  cir::FuncType ty = cgm.getTypes().getFunctionType(*fInfo);
+  CIRGenCallee callee = CIRGenCallee::forVirtual(ce, gd, thisAddr, ty);
+
+  bool isDeleting = dtorType == Dtor_Deleting;
+  bool isArrayDelete = de && de->isArrayForm() && vectorDeletingDtorsEnabled;
+  bool isGlobalDelete = de && de->isGlobalDelete() &&
+                        context.getTargetInfo().callGlobalDeleteInDeletingDtor(
+                            context.getLangOpts());
+  int32_t flags =
+      (isDeleting ? 1 : 0) | (isGlobalDelete ? 4 : 0) | (isArrayDelete ? 2 : 0);
+  mlir::Value implicitParam =
+      cgf.getBuilder().getSInt32(flags, cgf.getLoc(dtor->getLocation()));
+
+  QualType thisTy;
+  if (ce)
+    thisTy = ce->getObjectType();
+  else
+    thisTy = de->getDestroyedType();
+
+  while (const ArrayType *aTy = context.getAsArrayType(thisTy))
+    thisTy = aTy->getElementType();
+
+  thisAddr = adjustThisArgumentForVirtualFunctionCall(cgf, gd, thisAddr, true);
+  cgf.emitCXXDestructorCall(gd, callee, thisAddr.emitRawPointer(), thisTy,
+                            implicitParam, context.IntTy, ce);
+  return nullptr;
+}
+
+void CIRGenMicrosoftCXXABI::emitVirtualObjectDelete(
+    CIRGenFunction &cgf, const CXXDeleteExpr *de, Address ptr,
+    QualType elementType, const CXXDestructorDecl *dtor) {
+  if (!cgm.getASTContext().getTargetInfo().callGlobalDeleteInDeletingDtor(
+          cgm.getASTContext().getLangOpts())) {
+    cgf.cgm.errorNYI(de->getSourceRange(),
+                     "emitVirtualObjectDelete: legacy global delete without "
+                     "deleting dtor flag");
+    return;
   }
+  emitVirtualDestructorCall(cgf, dtor, Dtor_Deleting, ptr, de);
+}
 
-  void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override {
-    cgm.errorNYI(loc, "emitBadCastCall: MSVC ABI");
+const CXXRecordDecl *
+CIRGenMicrosoftCXXABI::getThisArgumentTypeForMethod(const CXXMethodDecl *md) {
+  if (md->isVirtual()) {
+    GlobalDecl lookupGD;
+    if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
+      lookupGD = GlobalDecl(
+          dd, cgm.getASTContext().getTargetInfo().emitVectorDeletingDtors(
+                  cgm.getASTContext().getLangOpts())
+                  ? Dtor_VectorDeleting
+                  : Dtor_Deleting);
+    } else {
+      lookupGD = GlobalDecl(md);
+    }
+    MethodVFTableLocation ml =
+        cgm.getMicrosoftVTableContext().getMethodVFTableLocation(lookupGD);
+    if (ml.VBase || !ml.VFPtrOffset.isZero())
+      return nullptr;
   }
+  return md->getParent();
+}
 
-  mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc,
-                              QualType srcRecordTy, QualType destRecordTy,
-                              cir::PointerType destCIRTy, bool isRefCast,
-                              Address src) override {
-    cgf.cgm.errorNYI(loc, "emitDynamicCast: MSVC ABI");
-    return cgf.getBuilder().getNullPtr(destCIRTy, loc);
+Address CIRGenMicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall(
+    CIRGenFunction &cgf, GlobalDecl gd, Address thisAddr, bool virtualCall) {
+  if (!virtualCall) {
+    CharUnits adjustment = getVirtualFunctionPrologueThisAdjustment(gd);
+    if (adjustment.isZero())
+      return thisAddr;
+
+    CIRGenBuilderTy &builder = cgf.getBuilder();
+    mlir::Location loc = cgf.getLoc(gd.getDecl()->getLocation());
+    cir::PointerType u8PtrTy = builder.getUInt8PtrTy();
+    mlir::Value u8This = builder.createBitcast(thisAddr.getPointer(), u8PtrTy);
+    assert(adjustment.isPositive());
+    mlir::Value adjConst = builder.getSInt32(adjustment.getQuantity(), loc);
+    mlir::Value adjusted =
+        cir::PtrStrideOp::create(builder, loc, u8PtrTy, u8This, adjConst);
+    return Address(builder.createBitcast(adjusted, thisAddr.getElementType()),
+                   thisAddr.getElementType(), thisAddr.getAlignment());
   }
 
-  mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
-                                          QualType ty) override {
-    cgm.errorNYI(loc, "getAddrOfRTTIDescriptor: MSVC ABI");
+  const auto *md = cast<CXXMethodDecl>(gd.getDecl());
+  GlobalDecl lookupGD = gd;
+  if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
+    if (gd.getDtorType() == Dtor_Complete)
+      return thisAddr;
+
+    lookupGD = GlobalDecl(
+        dd, cgm.getASTContext().getTargetInfo().emitVectorDeletingDtors(
+                cgm.getASTContext().getLangOpts())
+                ? Dtor_VectorDeleting
+                : Dtor_Deleting);
+  }
+  MethodVFTableLocation ml =
+      cgm.getMicrosoftVTableContext().getMethodVFTableLocation(lookupGD);
+
+  CharUnits staticOffset = ml.VFPtrOffset;
+  if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
+    staticOffset = CharUnits::Zero();
+
+  Address result = thisAddr;
+  CIRGenBuilderTy &builder = cgf.getBuilder();
+  mlir::Location loc = cgf.getLoc(gd.getDecl()->getLocation());
+  cir::PointerType u8PtrTy = builder.getUInt8PtrTy();
+
+  if (ml.VBase) {
+    const CXXRecordDecl *derived = md->getParent();
+    const CXXRecordDecl *vbase = ml.VBase;
+    mlir::Value vbaseOffset =
+        getVirtualBaseClassOffset(loc, cgf, result, derived, vbase);
+    mlir::Value rawPtr = builder.createBitcast(result.getPointer(), u8PtrTy);
+    mlir::Value vbasePtr =
+        cir::PtrStrideOp::create(builder, loc, u8PtrTy, rawPtr, vbaseOffset);
+    CharUnits vbaseAlign =
+        cgm.getVBaseAlignment(result.getAlignment(), derived, vbase);
+    result = Address(vbasePtr, builder.getUInt8Ty(), vbaseAlign);
+  }
+
+  if (!staticOffset.isZero()) {
+    assert(staticOffset.isPositive());
+    mlir::Value rawPtr = builder.createBitcast(result.getPointer(), u8PtrTy);
+    mlir::Value offsetVal = builder.getSInt32(staticOffset.getQuantity(), loc);
+    mlir::Value adjustedPtr =
+        cir::PtrStrideOp::create(builder, loc, u8PtrTy, rawPtr, offsetVal);
+    result = Address(adjustedPtr, builder.getUInt8Ty(),
+                     result.getAlignment().alignmentAtOffset(staticOffset));
+  }
+
+  if (result.getElementType() != thisAddr.getElementType()) {
+    mlir::Value castPtr =
+        builder.createBitcast(result.getPointer(), thisAddr.getElementType());
+    result = Address(castPtr, thisAddr.getElementType(), result.getAlignment());
+  }
+
+  return result;
+}
+
+cir::GlobalOp CIRGenMicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,
+                                                     CharUnits vptrOffset) {
+  VFTableIdTy id(rd, vptrOffset);
+  auto it = vftablesMap.find(id);
+  if (it != vftablesMap.end())
+    return it->second;
----------------
kazutakahirata wrote:

Could we use `try_emplace` here and bind `cir::GlobalOp &vtable = it->second;` so that we can assign to `vtable` directly and avoid repeating the `vftablesMap[id]` lookup later in this function?
```cpp
  VFTableIdTy id(rd, vptrOffset);
  auto [it, inserted] = vftablesMap.try_emplace(id);
  if (!inserted)
    return it->second;

  cir::GlobalOp &vtable = it->second;
```

https://github.com/llvm/llvm-project/pull/233291


More information about the cfe-commits mailing list