https://github.com/R-Goc created https://github.com/llvm/llvm-project/pull/233291
* Implement foundational CIRGenMicrosoftCXXABI class and driver wiring. * Implement string literal mangling (??_C@_). * Implement constructor this-return (hasThisReturn). * Add initial lit test in clang/test/CIR/CodeGen/cxx-msvc-abi.cpp. Assisted-by: Gemini:gemini-3.8-flash-high >From 98a5e903d2af6bf93321e08fa54b801890cfd5df Mon Sep 17 00:00:00 2001 From: R-Goc <[email protected]> Date: Fri, 16 Oct 2026 21:48:27 +0200 Subject: [PATCH] [CIR] Add initial Microsoft C++ ABI support in ClangIR * Implement foundational CIRGenMicrosoftCXXABI class and driver wiring. * Implement string literal mangling (??_C@_). * Implement constructor this-return (hasThisReturn). * Add initial lit test in clang/test/CIR/CodeGen/cxx-msvc-abi.cpp. Assisted-by: Gemini:gemini-3.8-flash-high --- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 14 +- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 1 - clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 7 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 +- .../lib/CIR/CodeGen/CIRGenMicrosoftCXXABI.cpp | 1135 ++++++++++++++--- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 45 +- clang/lib/CIR/CodeGen/CIRGenModule.h | 7 + clang/lib/CIR/CodeGen/CIRGenVTables.h | 8 + clang/lib/CIR/CodeGen/CIRGenerator.cpp | 12 +- .../TargetLowering/LowerMicrosoftCXXABI.cpp | 12 +- clang/test/CIR/CodeGen/cxx-msvc-abi.cpp | 124 +- 11 files changed, 1161 insertions(+), 208 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index c562e4308c1ab0..79a628e2f5b051 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -900,9 +900,6 @@ CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { ? astContext.VoidPtrTy : astContext.VoidTy; - assert(!theCXXABI.hasThisReturn(gd) && - "Please send PR with a test and remove this"); - assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); assert(!cir::MissingFeatures::opCallFnInfoOpts()); @@ -1038,13 +1035,10 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( : RequiredArgs::All; GlobalDecl gd(d, ctorKind); - if (theCXXABI.hasThisReturn(gd)) - cgm.errorNYI(d->getSourceRange(), - "arrangeCXXConstructorCall: hasThisReturn"); - if (theCXXABI.hasMostDerivedReturn(gd)) - cgm.errorNYI(d->getSourceRange(), - "arrangeCXXConstructorCall: hasMostDerivedReturn"); - CanQualType resultType = astContext.VoidTy; + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(gd) + ? astContext.VoidPtrTy + : astContext.VoidTy; assert(!cir::MissingFeatures::opCallFnInfoOpts()); assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 9e6ff99792500a..2ea99be02dc3f1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -1053,7 +1053,6 @@ void CIRGenFunction::enterDtorCleanups(const CXXDestructorDecl *dd, "only the Microsoft ABI passes an implicit deleting dtor param"); cgm.errorNYI(dd->getSourceRange(), "deleting destructor with conditional delete: MSVC ABI"); - } else { assert(!dd->getOperatorDelete()->isDestroyingOperatorDelete() && "destroying operator delete is handled by emitDestructorBody"); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index decddca749d835..e80a2e6498fc33 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -342,8 +342,11 @@ static void emitNullBaseClassInitialization(CIRGenFunction &cgf, stores.emplace_back(CharUnits::Zero(), nvSize); // Each store is split by the existence of a vbptr. - // TODO(cir): This only needs handling for the MS CXXABI. - assert(!cir::MissingFeatures::msabi()); + if (cgf.cgm.getTarget().getCXXABI().isMicrosoft() && base->getNumVBases()) { + cgf.cgm.errorNYI(base->getSourceRange(), + "emitNullBaseClassInitialization: MSVC vbptr splitting"); + return; + } // If the type contains a pointer to data member we can't memset it to zero. // Instead, create a null constant and copy it to the destination. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 1fa57c4087da2c..89030b720b3b43 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1082,9 +1082,9 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd, const auto *md = dyn_cast<CXXMethodDecl>(fd); if (md && md->isImplicitObjectMemberFunction()) { if (cgm.getCXXABI().hasThisReturn(gd)) - cgm.errorNYI(fd->getSourceRange(), "this return"); + retTy = md->getThisType(); else if (cgm.getCXXABI().hasMostDerivedReturn(gd)) - cgm.errorNYI(fd->getSourceRange(), "most derived return"); + retTy = getContext().VoidPtrTy; cgm.getCXXABI().buildThisParam(*this, args); } diff --git a/clang/lib/CIR/CodeGen/CIRGenMicrosoftCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenMicrosoftCXXABI.cpp index 276e3e93cdda0f..8e5dc211b6953d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenMicrosoftCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenMicrosoftCXXABI.cpp @@ -1,4 +1,4 @@ -//===--- CIRGenMicrosoftCXXABI.cpp - Emit CIR Code for MS C++ ABI --------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,10 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ code generation targeting the Microsoft C++ ABI. +// This provides C++ code generation targeting the Microsoft C++ ABI. The class +// in this file generates structures that follow the Microsoft C++ ABI, which is +// documented at: +// https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 // //===----------------------------------------------------------------------===// @@ -14,95 +17,219 @@ #include "CIRGenFunction.h" #include "CIRGenModule.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Mangle.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CIR/MissingFeatures.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::CIRGen; namespace { +static bool isDeletingDtor(GlobalDecl gd) { + return isa<CXXDestructorDecl>(gd.getDecl()) && + (gd.getDtorType() == Dtor_Deleting || + gd.getDtorType() == Dtor_VectorDeleting); +} + +static QualType decomposeTypeForEH(ASTContext &context, QualType t, + bool &isConst, bool &isVolatile, + bool &isUnaligned) { + t = context.getExceptionObjectType(t); + isConst = false; + isVolatile = false; + isUnaligned = false; + QualType pointeeType = t->getPointeeType(); + if (!pointeeType.isNull()) { + isConst = pointeeType.isConstQualified(); + isVolatile = pointeeType.isVolatileQualified(); + isUnaligned = pointeeType.getQualifiers().hasUnaligned(); + } + if (const auto *mpty = t->getAs<MemberPointerType>()) + t = context.getMemberPointerType(pointeeType.getUnqualifiedType(), + mpty->getQualifier(), + mpty->getMostRecentCXXRecordDecl()); + if (t->isPointerType()) + t = context.getPointerType(pointeeType.getUnqualifiedType()); + return t; +} + class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { + using VFTableIdTy = std::pair<const CXXRecordDecl *, CharUnits>; + llvm::DenseMap<VFTableIdTy, cir::GlobalOp> vftablesMap; + + MicrosoftMangleContext &getMangleContext() { + return *cast<MicrosoftMangleContext>(mangleContext.get()); + } + + CharUnits getVirtualFunctionPrologueThisAdjustment(GlobalDecl gd); + + mlir::Value getVBaseOffsetFromVBPtr(CIRGenFunction &cgf, mlir::Location loc, + Address thisAddr, int64_t vbPtrOffset, + unsigned vbTableIndex, + mlir::Value *vbPtrOut = nullptr); + public: CIRGenMicrosoftCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {} + bool hasThisReturn(clang::GlobalDecl gd) const override { + return isa<CXXConstructorDecl>(gd.getDecl()); + } + + bool hasMostDerivedReturn(clang::GlobalDecl gd) const override { + return false; + } + + llvm::StringRef getPureVirtualCallName() override { return "_purecall"; } + llvm::StringRef getDeletedVirtualCallName() override { return "_purecall"; } + + bool canSpeculativelyEmitVTable(const CXXRecordDecl *rd) const override { + return false; + } + + bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override { + return !vtableClass->hasAttr<MSNoVTableAttr>(); + } + + bool exportThunk() override { return false; } + + bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, + CXXDtorType dt) const override { + return dt != Dtor_Base; + } + + bool isZeroInitializable(const MemberPointerType *mpt) override { + if (mpt->isMemberFunctionPointer()) + return true; + + const CXXRecordDecl *rd = mpt->getMostRecentCXXRecordDecl(); + MSInheritanceModel inheritance = rd->getMSInheritanceModel(); + return (!inheritanceModelHasVBTableOffsetField(inheritance) && + rd->nullFieldOffsetIsZero()); + } + + bool requiresArrayCookie(const CXXNewExpr *e) override { + return e->getAllocatedType().isDestructedType(); + } + + CharUnits getArrayCookieSizeImpl(QualType elementType) override { + ASTContext &ctx = cgm.getASTContext(); + return std::max(ctx.getTypeSizeInChars(ctx.getSizeType()), + ctx.getTypeAlignInChars(elementType)); + } + + Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr, + mlir::Value numElements, const CXXNewExpr *e, + QualType elementType) override; + + cir::GlobalLinkageKind + getCXXDestructorLinkage(GVALinkage linkage, const CXXDestructorDecl *dtor, + CXXDtorType dt) const override { + if (linkage == GVA_Internal) + return cir::GlobalLinkageKind::InternalLinkage; + + switch (dt) { + case Dtor_Base: + return cgm.getCIRLinkageForDeclarator(dtor, linkage); + case Dtor_Complete: + if (dtor->hasAttr<DLLExportAttr>()) + return cir::GlobalLinkageKind::WeakODRLinkage; + return linkage == GVA_DiscardableODR + ? cir::GlobalLinkageKind::LinkOnceODRLinkage + : cir::GlobalLinkageKind::WeakODRLinkage; + case Dtor_Deleting: + case Dtor_VectorDeleting: + return cir::GlobalLinkageKind::LinkOnceODRLinkage; + case Dtor_Comdat: + llvm_unreachable("emitting dtor comdat as function?"); + case Dtor_Unified: + llvm_unreachable("unexpected unified dtor type"); + } + llvm_unreachable("invalid dtor type"); + } + + void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd, + bool returnAdjustment) override { + GVALinkage linkage = cgm.getASTContext().GetGVALinkageForFunction( + cast<FunctionDecl>(gd.getDecl())); + + if (linkage == GVA_Internal) + thunk.setLinkage(cir::GlobalLinkageKind::InternalLinkage); + else if (returnAdjustment) + thunk.setLinkage(cir::GlobalLinkageKind::WeakODRLinkage); + else + thunk.setLinkage(cir::GlobalLinkageKind::LinkOnceODRLinkage); + } + + CatchTypeInfo getCatchAllTypeInfo() override { + if (cgm.getASTContext().getLangOpts().EHAsynch) + return CatchTypeInfo{nullptr, 0}; + else + return CatchTypeInfo{nullptr, 0x40}; + } + + void adjustCallArgsForDestructorThunk(CIRGenFunction &cgf, GlobalDecl gd, + CallArgList &callArgs) override { + assert((gd.getDtorType() == Dtor_VectorDeleting || + gd.getDtorType() == Dtor_Deleting) && + "Only vector deleting destructor thunks are available in this ABI"); + callArgs.add(RValue::get(getStructorImplicitParamValue(cgf)), + cgm.getASTContext().IntTy); + } + AddedStructorArgCounts buildStructorSignature(GlobalDecl gd, - SmallVectorImpl<CanQualType> &argTys) override { - cgm.errorNYI(gd.getDecl()->getSourceRange(), - "buildStructorSignature: MSVC ABI"); - return AddedStructorArgCounts{}; - } + llvm::SmallVectorImpl<CanQualType> &argTys) override; void addImplicitStructorParams(CIRGenFunction &cgf, QualType &resTy, - FunctionArgList ¶ms) override { - cgf.cgm.errorNYI(cgf.curGD.getDecl()->getSourceRange(), - "addImplicitStructorParams: MSVC ABI"); - } + FunctionArgList ¶ms) override; void emitInstanceFunctionProlog(SourceLocation loc, - CIRGenFunction &cgf) override { - cgf.cgm.errorNYI(loc, "emitInstanceFunctionProlog: MSVC ABI"); - } + CIRGenFunction &cgf) override; AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, - bool delegating) override { - cgf.cgm.errorNYI(d->getSourceRange(), - "getImplicitConstructorArgs: MSVC ABI"); - return AddedStructorArgs{}; - } + bool delegating) override; mlir::Value getCXXDestructorImplicitParam(CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating) override { - cgf.cgm.errorNYI(dd->getSourceRange(), - "getCXXDestructorImplicitParam: MSVC ABI"); return nullptr; } - void emitCXXConstructors(const CXXConstructorDecl *d) override { - cgm.errorNYI(d->getSourceRange(), "emitCXXConstructors: MSVC ABI"); - } - - void emitCXXDestructors(const CXXDestructorDecl *d) override { - cgm.errorNYI(d->getSourceRange(), "emitCXXDestructors: MSVC ABI"); - } - - void emitCXXStructor(GlobalDecl gd) override { - cgm.errorNYI(gd.getDecl()->getSourceRange(), "emitCXXStructor: MSVC ABI"); - } + void emitCXXConstructors(const CXXConstructorDecl *d) override; + void emitCXXDestructors(const CXXDestructorDecl *d) override; + void emitCXXStructor(GlobalDecl gd) override; void emitDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating, Address thisAddr, - QualType thisTy) override { - cgf.cgm.errorNYI(dd->getSourceRange(), "emitDestructorCall: MSVC ABI"); - } + QualType thisTy) override; mlir::Value emitVirtualDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType, Address thisAddr, - DeleteOrMemberCallExpr e) override { - cgf.cgm.errorNYI(dtor->getSourceRange(), - "emitVirtualDestructorCall: MSVC ABI"); - return nullptr; - } + DeleteOrMemberCallExpr e) override; void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de, Address ptr, QualType elementType, - const CXXDestructorDecl *dtor) override { - cgf.cgm.errorNYI(de->getSourceRange(), "emitVirtualObjectDelete: MSVC ABI"); - } + const CXXDestructorDecl *dtor) override; size_t getSrcArgforCopyCtor(const CXXConstructorDecl *cd, FunctionArgList &args) const override { - cgm.errorNYI(cd->getSourceRange(), "getSrcArgforCopyCtor: MSVC ABI"); assert(args.size() >= 2 && "expected the arglist to have at least two args!"); // The 'most_derived' parameter goes second if the ctor is variadic and @@ -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 ¶ms) { + 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; + + MicrosoftVTableContext &vtContext = cgm.getMicrosoftVTableContext(); + const VPtrInfoVector &vfptrs = vtContext.getVFPtrOffsets(rd); + + const std::unique_ptr<VPtrInfo> *vfptrI = + llvm::find_if(vfptrs, [&](const std::unique_ptr<VPtrInfo> &vpi) { + return vpi->FullOffsetInMDC == vptrOffset; + }); + if (vfptrI == vfptrs.end()) { + vftablesMap[id] = nullptr; return nullptr; } + const std::unique_ptr<VPtrInfo> &vfptr = *vfptrI; - CatchTypeInfo getCatchAllTypeInfo() override { - cgm.errorNYI("getCatchAllTypeInfo: MSVC ABI"); - return CatchTypeInfo{nullptr, 0}; + SmallString<256> vftableName; + { + llvm::raw_svector_ostream out(vftableName); + getMangleContext().mangleCXXVFTable(rd, vfptr->MangledPath, out); } - CatchTypeInfo - getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty, - QualType catchHandlerType) override { - cgm.errorNYI(loc, "getAddrOfCXXCatchHandlerType: MSVC ABI"); - return CatchTypeInfo{nullptr, 0}; + if (auto gv = cgm.getGlobalValue(vftableName)) { + auto globalOp = dyn_cast<cir::GlobalOp>(gv); + vftablesMap[id] = globalOp; + return globalOp; } - void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override { - cgm.errorNYI("emitRethrow: MSVC ABI"); + cir::GlobalLinkageKind linkage = + rd->hasAttr<DLLImportAttr>() ? cir::GlobalLinkageKind::LinkOnceODRLinkage + : cgm.getVTableLinkage(rd); + + cir::GlobalOp vtable = + cgm.createGlobalOp(cgm.getLoc(rd->getLocation()), vftableName, + cgm.getVTableComponentType(), /*isConstant=*/true); + vtable.setLinkage(linkage); + + if (rd->hasAttr<DLLExportAttr>()) + vtable.setVisibility(mlir::SymbolTable::Visibility::Public); + + vftablesMap[id] = vtable; + return vtable; +} + +mlir::Value +CIRGenMicrosoftCXXABI::getVTableAddressPoint(BaseSubobject base, + const CXXRecordDecl *vtableClass) { + cir::GlobalOp vtable = getAddrOfVTable(vtableClass, base.getBaseOffset()); + if (!vtable) + return nullptr; + + mlir::OpBuilder &builder = cgm.getBuilder(); + auto vtablePtrTy = cir::VPtrType::get(builder.getContext()); + + return cir::VTableAddrPointOp::create( + builder, cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy, + mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()), + cir::AddressPointAttr::get(cgm.getBuilder().getContext(), + /*vtableIndex=*/0, + /*addressPointIndex=*/0)); +} + +mlir::Value CIRGenMicrosoftCXXABI::getVTableAddressPointInStructor( + CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base, + const CXXRecordDecl *nearestVBase) { + return getVTableAddressPoint(base, vtableClass); +} + +CIRGenCallee CIRGenMicrosoftCXXABI::getVirtualFunctionPointer( + CIRGenFunction &cgf, GlobalDecl gd, Address thisAddr, mlir::Type ty, + SourceLocation loc) { + CIRGenBuilderTy &builder = cgm.getBuilder(); + mlir::Location mlirLoc = cgf.getLoc(loc); + cir::PointerType tyPtr = builder.getPointerTo(ty); + auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl()); + + Address vptr = adjustThisArgumentForVirtualFunctionCall(cgf, gd, thisAddr, + /*virtualCall=*/true); + mlir::Value vtable = cgf.getVTablePtr(mlirLoc, vptr, methodDecl->getParent()); + + MicrosoftVTableContext &vftContext = cgm.getMicrosoftVTableContext(); + MethodVFTableLocation ml = vftContext.getMethodVFTableLocation(gd); + + mlir::Value vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create( + builder, mlirLoc, builder.getPointerTo(tyPtr), vtable, ml.Index); + mlir::Value vfunc = builder.createAlignedLoad(mlirLoc, tyPtr, vtableSlotPtr, + cgf.getPointerAlign()); + + return CIRGenCallee(gd, vfunc.getDefiningOp()); +} + +void CIRGenMicrosoftCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt, + const CXXRecordDecl *rd) { + MicrosoftVTableContext &vftContext = cgm.getMicrosoftVTableContext(); + const VPtrInfoVector &vfptrs = vftContext.getVFPtrOffsets(rd); + + for (const auto &info : vfptrs) { + cir::GlobalOp vtable = getAddrOfVTable(rd, info->FullOffsetInMDC); + if (!vtable || vtable.hasInitializer()) + continue; + + const VTableLayout &vtLayout = + vftContext.getVFTableLayout(rd, info->FullOffsetInMDC); + cir::GlobalLinkageKind linkage = + rd->hasAttr<DLLImportAttr>() + ? cir::GlobalLinkageKind::LinkOnceODRLinkage + : cgm.getVTableLinkage(rd); + + mlir::Attribute rtti = nullptr; + if (cgm.getASTContext().getLangOpts().RTTIData && + llvm::any_of( + vtLayout.vtable_components(), + [](const VTableComponent &vtc) { return vtc.isRTTIKind(); })) { + rtti = + getAddrOfRTTIDescriptor(cgm.getLoc(rd->getLocation()), + cgm.getASTContext().getCanonicalTagType(rd)); + } + + cgvt.createVTableInitializer(vtable, vtLayout, rtti, + cir::isLocalLinkage(linkage)); + vtable.setLinkage(linkage); + if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage)) + vtable.setSelfComdat(); + cgm.setGVProperties(vtable, rd); } +} + +void CIRGenMicrosoftCXXABI::emitVirtualInheritanceTables( + const CXXRecordDecl *rd) { + if (!rd->getNumVBases()) + return; + cgm.errorNYI(rd->getSourceRange(), + "emitVirtualInheritanceTables: MSVC VBTables"); +} + +void CIRGenMicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers( + CIRGenFunction &cgf, const CXXRecordDecl *rd) { + if (!rd->getNumVBases()) + return; + cgf.cgm.errorNYI(rd->getSourceRange(), + "initializeHiddenVirtualInheritanceMembers: vbptr stores"); +} + +mlir::Value CIRGenMicrosoftCXXABI::getVirtualBaseClassOffset( + mlir::Location loc, CIRGenFunction &cgf, Address thisAddr, + const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) { + const ASTContext &context = cgm.getASTContext(); + CIRGenBuilderTy &builder = cgf.getBuilder(); + + int64_t vbPtrChars = + context.getASTRecordLayout(classDecl).getVBPtrOffset().getQuantity(); + unsigned vbIndex = + cgm.getMicrosoftVTableContext().getVBTableIndex(classDecl, baseClassDecl); + + mlir::Value vbaseOffset = + getVBaseOffsetFromVBPtr(cgf, loc, thisAddr, vbPtrChars, vbIndex); + + mlir::Type ptrDiffTy = cgm.ptrDiffTy; + mlir::Value vbaseOffsetCast = builder.createIntCast(vbaseOffset, ptrDiffTy); + mlir::Value vbPtrOffsetCast = + builder.getConstantInt(loc, ptrDiffTy, vbPtrChars); + return builder.createAdd(loc, vbPtrOffsetCast, vbaseOffsetCast); +} - void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override { - cgf.cgm.errorNYI(e->getSourceRange(), "emitThrow: MSVC ABI"); +cir::MethodAttr +CIRGenMicrosoftCXXABI::buildVirtualMethodAttr(cir::MethodType methodTy, + const CXXMethodDecl *md) { + assert(md->isVirtual() && "only deal with virtual member functions"); + + MethodVFTableLocation ml = + cgm.getMicrosoftVTableContext().getMethodVFTableLocation(md); + const ASTContext &astContext = cgm.getASTContext(); + CharUnits pointerWidth = astContext.toCharUnitsFromBits( + astContext.getTargetInfo().getPointerWidth(LangAS::Default)); + uint64_t vtableOffset = ml.Index * pointerWidth.getQuantity(); + + return cir::MethodAttr::get(methodTy, vtableOffset); +} + +mlir::Value CIRGenMicrosoftCXXABI::performThisAdjustment( + CIRGenFunction &cgf, Address thisAddr, const CXXRecordDecl *unadjustedClass, + const ThunkInfo &ti) { + const ThisAdjustment &ta = ti.This; + if (ta.isEmpty()) + return thisAddr.emitRawPointer(); + + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc( + unadjustedClass ? unadjustedClass->getLocation() : SourceLocation()); + cir::PointerType u8PtrTy = builder.getUInt8PtrTy(); + mlir::Value v = builder.createBitcast(thisAddr.getPointer(), u8PtrTy); + + if (!ta.Virtual.isEmpty()) { + assert(ta.Virtual.Microsoft.VtordispOffset < 0); + mlir::Value vtorDispOffset = + builder.getSInt32(ta.Virtual.Microsoft.VtordispOffset, loc); + mlir::Value vtorDispPtr = + cir::PtrStrideOp::create(builder, loc, u8PtrTy, v, vtorDispOffset); + mlir::Type i32Ty = builder.getSInt32Ty(); + mlir::Value vtorDispI32Ptr = + builder.createBitcast(vtorDispPtr, builder.getPointerTo(i32Ty)); + mlir::Value vtorDisp = builder.createLoad( + loc, Address(vtorDispI32Ptr, i32Ty, CharUnits::fromQuantity(4))); + mlir::Value negVtorDisp = builder.createNeg(loc, vtorDisp); + v = cir::PtrStrideOp::create(builder, loc, u8PtrTy, v, negVtorDisp); + + if (ta.Virtual.Microsoft.VBPtrOffset) { + assert(ta.Virtual.Microsoft.VBPtrOffset > 0); + assert(ta.Virtual.Microsoft.VBOffsetOffset >= 0); + mlir::Value vbPtr; + unsigned vbTableIndex = ta.Virtual.Microsoft.VBOffsetOffset / 4; + mlir::Value vbaseOffset = getVBaseOffsetFromVBPtr( + cgf, loc, Address(v, builder.getUInt8Ty(), cgf.getPointerAlign()), + -ta.Virtual.Microsoft.VBPtrOffset, vbTableIndex, &vbPtr); + v = cir::PtrStrideOp::create(builder, loc, u8PtrTy, vbPtr, vbaseOffset); + } } - void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor, - mlir::Value addr) override { - cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: MSVC ABI"); + if (ta.NonVirtual) { + mlir::Value nonVirt = builder.getSInt32(ta.NonVirtual, loc); + v = cir::PtrStrideOp::create(builder, loc, u8PtrTy, v, nonVirt); } -}; -} // namespace + return builder.createBitcast(v, thisAddr.getElementType()); +} + +mlir::Value CIRGenMicrosoftCXXABI::performReturnAdjustment( + CIRGenFunction &cgf, Address ret, const CXXRecordDecl *unadjustedClass, + const ReturnAdjustment &ra) { + if (ra.isEmpty()) + return ret.emitRawPointer(); + + CIRGenBuilderTy &builder = cgf.getBuilder(); + mlir::Location loc = cgf.getLoc( + unadjustedClass ? unadjustedClass->getLocation() : SourceLocation()); + cir::PointerType u8PtrTy = builder.getUInt8PtrTy(); + mlir::Value v = builder.createBitcast(ret.getPointer(), u8PtrTy); + + if (ra.Virtual.Microsoft.VBIndex) { + assert(ra.Virtual.Microsoft.VBIndex > 0); + mlir::Value vbPtr; + mlir::Value vbaseOffset = + getVBaseOffsetFromVBPtr(cgf, loc, ret, ra.Virtual.Microsoft.VBPtrOffset, + ra.Virtual.Microsoft.VBIndex, &vbPtr); + v = cir::PtrStrideOp::create(builder, loc, u8PtrTy, vbPtr, vbaseOffset); + } + + if (ra.NonVirtual) { + mlir::Value nonVirt = builder.getSInt32(ra.NonVirtual, loc); + v = cir::PtrStrideOp::create(builder, loc, u8PtrTy, v, nonVirt); + } + + return builder.createBitcast(v, ret.getElementType()); +} + +bool CIRGenMicrosoftCXXABI::shouldTypeidBeNullChecked(QualType srcTy) { + const CXXRecordDecl *srcDecl = srcTy->getAsCXXRecordDecl(); + return !cgm.getASTContext().getASTRecordLayout(srcDecl).hasExtendableVFPtr(); +} + +mlir::Value CIRGenMicrosoftCXXABI::emitTypeid(CIRGenFunction &cgf, + QualType srcTy, Address thisPtr, + mlir::Type typeInfoPtrTy) { + cgf.cgm.errorNYI(cgf.getLoc(srcTy->getAsCXXRecordDecl()->getLocation()), + "emitTypeid: MSVC ABI"); + return cgf.getBuilder().getNullPtr( + typeInfoPtrTy, cgf.getLoc(srcTy->getAsCXXRecordDecl()->getLocation())); +} + +void CIRGenMicrosoftCXXABI::emitBadTypeidCall(CIRGenFunction &cgf, + mlir::Location loc) { + cgf.cgm.errorNYI(loc, "emitBadTypeidCall: MSVC ABI"); + cir::UnreachableOp::create(cgf.getBuilder(), loc); +} + +void CIRGenMicrosoftCXXABI::emitBadCastCall(CIRGenFunction &cgf, + mlir::Location loc) { + cgm.errorNYI(loc, "emitBadCastCall: MSVC ABI"); +} + +mlir::Value CIRGenMicrosoftCXXABI::emitDynamicCast( + CIRGenFunction &cgf, mlir::Location loc, QualType srcRecordTy, + QualType destRecordTy, cir::PointerType destCIRTy, bool isRefCast, + Address src) { + cgf.cgm.errorNYI(loc, "emitDynamicCast: MSVC ABI"); + return cgf.getBuilder().getNullPtr(destCIRTy, loc); +} + +mlir::Attribute +CIRGenMicrosoftCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc, + QualType ty) { + SmallString<256> mangledName; + { + llvm::raw_svector_ostream out(mangledName); + getMangleContext().mangleCXXRTTI(ty, out); + } + + CIRGenBuilderTy &builder = cgm.getBuilder(); + cir::PointerType voidPtrTy = builder.getVoidPtrTy(); + + if (auto gv = cgm.getGlobalValue(mangledName)) + return builder.getGlobalViewAttr(voidPtrTy, cast<cir::GlobalOp>(gv)); + + cir::GlobalOp gv = + cgm.createGlobalOp(loc, mangledName, voidPtrTy, /*isConstant=*/true); + gv.setLinkage(cir::GlobalLinkageKind::ExternalLinkage); + return builder.getGlobalViewAttr(voidPtrTy, gv); +} + +CatchTypeInfo CIRGenMicrosoftCXXABI::getAddrOfCXXCatchHandlerType( + mlir::Location loc, QualType ty, QualType catchHandlerType) { + bool isConst, isVolatile, isUnaligned; + ty = decomposeTypeForEH(cgm.getASTContext(), ty, isConst, isVolatile, + isUnaligned); + + bool isReference = catchHandlerType->isReferenceType(); + + uint32_t flags = 0; + if (isConst) + flags |= 1; + if (isVolatile) + flags |= 2; + if (isUnaligned) + flags |= 4; + if (isReference) + flags |= 8; + + auto rtti = dyn_cast<cir::GlobalViewAttr>(getAddrOfRTTIDescriptor(loc, ty)); + assert(rtti && "expected GlobalViewAttr"); + return CatchTypeInfo{rtti, flags}; +} + +void CIRGenMicrosoftCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) { + if (isNoReturn) { + CIRGenBuilderTy &builder = cgf.getBuilder(); + assert(cgf.currSrcLoc && "expected source location"); + mlir::Location loc = cgf.getLoc(*cgf.currSrcLoc); + cir::ThrowOp::create(builder, loc, mlir::Value(), mlir::FlatSymbolRefAttr(), + mlir::FlatSymbolRefAttr()); + cir::UnreachableOp::create(builder, loc); + } else { + cgm.errorNYI("emitRethrow with isNoReturn false: MSVC ABI"); + } +} + +void CIRGenMicrosoftCXXABI::emitThrow(CIRGenFunction &cgf, + const CXXThrowExpr *e) { + cgf.cgm.errorNYI(e->getSourceRange(), "emitThrow: MSVC ABI"); +} + +void CIRGenMicrosoftCXXABI::registerGlobalDtor(const VarDecl *vd, + cir::FuncOp dtor, + mlir::Value addr) { + if (vd->isNoDestroy(cgm.getASTContext())) + return; + + if (cgm.getLangOpts().HLSL) { + cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: HLSL"); + return; + } +} CIRGenCXXABI *clang::CIRGen::CreateCIRGenMicrosoftCXXABI(CIRGenModule &cgm) { return new CIRGenMicrosoftCXXABI(cgm); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 614a731158e455..95eb6f56e8c1cb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2178,7 +2178,7 @@ cir::GlobalLinkageKind CIRGenModule::getFunctionLinkage(GlobalDecl gd) { static cir::GlobalOp generateStringLiteral(mlir::Location loc, mlir::TypedAttr c, - cir::GlobalLinkageKind lt, CIRGenModule &cgm, + cir::GlobalLinkageKind linkageKind, CIRGenModule &cgm, StringRef globalName, CharUnits alignment) { LangAS as = CodeGenUtils::getGlobalConstantAddressSpace(cgm.getLangOpts(), cgm.getTarget()); @@ -2193,8 +2193,8 @@ generateStringLiteral(mlir::Location loc, mlir::TypedAttr c, // Set up extra information and add to the module gv.setAlignmentAttr(cgm.getSize(alignment)); - gv.setLinkageAttr( - cir::GlobalLinkageKindAttr::get(cgm.getBuilder().getContext(), lt)); + gv.setLinkageAttr(cir::GlobalLinkageKindAttr::get( + cgm.getBuilder().getContext(), linkageKind)); assert(!cir::MissingFeatures::opGlobalThreadLocal()); assert(!cir::MissingFeatures::opGlobalUnnamedAddr()); CIRGenModule::setInitializer(gv, c); @@ -2246,27 +2246,38 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s, uint64_t(alignment.getQuantity()) > *gv.getAlignment()) gv.setAlignmentAttr(getSize(alignment)); } else { + std::string globalVariableName; + cir::GlobalLinkageKind linkageKind; + // Mangle the string literal if that's how the ABI merges duplicate strings. // Don't do it if they are writable, since we don't want writes in one TU to // affect strings in another. if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) && !getLangOpts().WritableStrings) { - errorNYI(s->getSourceRange(), - "getGlobalForStringLiteral: mangle string literals"); + llvm::raw_string_ostream out(globalVariableName); + getCXXABI().getMangleContext().mangleStringLiteral(s, out); + linkageKind = cir::GlobalLinkageKind::LinkOnceODRLinkage; + } else { + linkageKind = cir::GlobalLinkageKind::PrivateLinkage; + // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so + // we need to do that explicitly. + globalVariableName = getUniqueGlobalName(name.str()); + } + + if (auto existingGV = getGlobalValue(globalVariableName)) { + gv = cast<cir::GlobalOp>(existingGV); + constantStringMap[c] = gv; + return gv; } - // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so - // we need to do that explicitly. - std::string uniqueName = getUniqueGlobalName(name.str()); // Synthetic string literals (e.g., from SourceLocExpr) may not have valid // source locations. Use unknown location in those cases. mlir::Location loc = s->getBeginLoc().isValid() ? getLoc(s->getSourceRange()) : builder.getUnknownLoc(); auto typedC = llvm::cast<mlir::TypedAttr>(c); - gv = generateStringLiteral(loc, typedC, - cir::GlobalLinkageKind::PrivateLinkage, *this, - uniqueName, alignment); + gv = generateStringLiteral(loc, typedC, linkageKind, *this, + globalVariableName, alignment); setDSOLocal(static_cast<mlir::Operation *>(gv)); constantStringMap[c] = gv; @@ -2907,9 +2918,10 @@ StringRef CIRGenModule::getMangledName(GlobalDecl gd) { // constructors get mangled the same. if (const auto *cd = dyn_cast<CXXConstructorDecl>(canonicalGd.getDecl())) { if (!getTarget().getCXXABI().hasConstructorVariants()) { - errorNYI(cd->getSourceRange(), - "getMangledName: C++ constructor without variants"); - return cast<NamedDecl>(gd.getDecl())->getIdentifier()->getName(); + CXXCtorType origCtorType = gd.getCtorType(); + assert(origCtorType == Ctor_Base || origCtorType == Ctor_Complete); + if (origCtorType == Ctor_Base) + canonicalGd = GlobalDecl(cd, Ctor_Complete); } } @@ -3745,12 +3757,13 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction( } // All MSVC dtors other than the base dtor are linkonce_odr and delegate to - // each other bottoming out wiht the base dtor. Therefore we emit non-base + // each other bottoming out with the base dtor. Therefore we emit non-base // dtors on usage, even if there is no dtor definition in the TU. if (isa_and_nonnull<CXXDestructorDecl>(d) && getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(d), gd.getDtorType())) - errorNYI(d->getSourceRange(), "getOrCreateCIRFunction: dtor"); + errorNYI(d->getSourceRange(), + "getOrCreateCIRFunction: MSVC non-base destructor thunk"); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 80bf5940e461ea..aa450e6ce45ee2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -591,6 +591,13 @@ class CIRGenModule : public CIRGenTypeCache { return vtables.getItaniumVTableContext(); } + MicrosoftVTableContext &getMicrosoftVTableContext() { + return vtables.getMicrosoftVTableContext(); + } + const MicrosoftVTableContext &getMicrosoftVTableContext() const { + return vtables.getMicrosoftVTableContext(); + } + /// This contains all the decls which have definitions but which are deferred /// for emission and therefore should only be output if they are actually /// used. If a decl is in this, then it is known to have not been referenced diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h index 1e4da7d8f945f0..29fde7445c9465 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.h +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h @@ -76,6 +76,14 @@ class CIRGenVTables { return *llvm::cast<clang::ItaniumVTableContext>(vtContext); } + clang::MicrosoftVTableContext &getMicrosoftVTableContext() { + return *cast<clang::MicrosoftVTableContext>(vtContext); + } + + const clang::MicrosoftVTableContext &getMicrosoftVTableContext() const { + return *cast<clang::MicrosoftVTableContext>(vtContext); + } + /// Generate a construction vtable for the given base subobject. cir::GlobalOp generateConstructionVTable(const CXXRecordDecl *rd, const BaseSubobject &base, diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index bc0aed0b01ff03..e7b47ae0169779 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -160,8 +160,16 @@ void CIRGenerator::HandleTagDeclDefinition(TagDecl *d) { // For MSVC compatibility, treat declarations of static data members with // inline initializers as definitions. - if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) - cgm->errorNYI(d->getSourceRange(), "HandleTagDeclDefinition: MSABI"); + if (astContext->getTargetInfo().getCXXABI().isMicrosoft()) { + for (Decl *member : d->decls()) { + if (auto *vd = dyn_cast<VarDecl>(member)) { + if (astContext->isMSStaticDataMemberInlineDefinition(vd) && + astContext->DeclMustBeEmitted(vd)) { + cgm->emitGlobal(vd); + } + } + } + } // For OpenMP emit declare reduction functions or declare mapper, if // required. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerMicrosoftCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerMicrosoftCXXABI.cpp index 1cd7306d74dba9..ffb913e0459191 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerMicrosoftCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerMicrosoftCXXABI.cpp @@ -1,4 +1,5 @@ -//===---- LowerMicrosoftCXXABI.cpp - Emit CIR for Microsoft-specific code -===// +//===---- LowerMicrosoftCXXABI.cpp - Emit CIR code Microsoft-specific code +//-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -136,7 +137,9 @@ class LowerMicrosoftCXXABI : public CIRCXXABI { clang::CharUnits getArrayCookieSizeImpl(clang::CharUnits elementAlign) const override { - llvm_unreachable("Microsoft ABI array cookie lowering NYI"); + clang::CharUnits cookieSize = + clang::CharUnits::fromQuantity(getPtrSizeInBits() / 8); + return std::max(cookieSize, elementAlign); } mlir::Value readArrayCookieImpl(mlir::Location loc, mlir::Value allocPtr, @@ -144,7 +147,10 @@ class LowerMicrosoftCXXABI : public CIRCXXABI { clang::CharUnits cookieAlignment, const mlir::DataLayout &dataLayout, CIRBaseBuilderTy &builder) const override { - llvm_unreachable("Microsoft ABI array cookie lowering NYI"); + mlir::Type sizeTy = builder.getUIntNTy(getPtrSizeInBits()); + mlir::Value cookiePtr = + builder.createBitcast(allocPtr, builder.getPointerTo(sizeTy)); + return builder.createLoad(loc, cookiePtr); } }; diff --git a/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp b/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp index e1a4d7519f5d46..4e3f3ab3800cda 100644 --- a/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp +++ b/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp @@ -1,6 +1,126 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++17 -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s -void empty() {} +// Adapted from Clang CodeGenCXX/microsoft-abi-methods.cpp, +// microsoft-abi-structors.cpp, and microsoft-abi-vftables.cpp. -// CIR: cir.func {{.*}} @"?empty@@YAXXZ"() +//===----------------------------------------------------------------------===// +// Section 1: Member Functions & Calling Conventions +//===----------------------------------------------------------------------===// + +class MethodsTest { +public: + void simple_method() {} + void vararg_method(const char *fmt, ...) {} + static void static_method() {} +}; + +void call_methods() { + MethodsTest obj; + obj.simple_method(); + obj.vararg_method("test"); + MethodsTest::static_method(); +} + +// CIR-DAG: cir.global {{.*}} linkonce_odr {{.*}} @"??_C@_ +// CIR-DAG: cir.func {{.*}} @"?simple_method@MethodsTest@@QEAAXXZ"(%{{.*}}: !cir.ptr<!rec_MethodsTest> +// CIR-DAG: cir.func {{.*}} @"?vararg_method@MethodsTest@@QEAAXPEBDZZ"(%{{.*}}: !cir.ptr<!rec_MethodsTest>{{.*}}, %{{.*}}: !cir.ptr<!s8i>{{.*}}, ...) +// CIR-DAG: cir.func {{.*}} @"?static_method@MethodsTest@@SAXXZ"() + +//===----------------------------------------------------------------------===// +// Section 2: Structors and 'this' Return Calling Convention +//===----------------------------------------------------------------------===// + +class BasicA { + int x; +public: + BasicA() { x = 42; } + ~BasicA(); +}; + +BasicA::~BasicA() {} + +// Destructors return void. +// CIR-LABEL: cir.func {{.*}} @"??1BasicA@@QEAA@XZ" + +void test_basic() { + BasicA a; +} + +// In the MSVC ABI, constructors return 'this' (hasThisReturn is true). +// CIR-LABEL: cir.func {{.*}} @"??0BasicA@@QEAA@XZ" +// CIR-SAME: (%[[THIS_ARG:.*]]: !cir.ptr<!rec_BasicA>{{.*}}) -> (!cir.ptr<!rec_BasicA> +// CIR: %[[RETVAL:.*]] = cir.alloca "__retval" +// CIR: %[[THIS_ALLOCA:.*]] = cir.alloca "this" +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]] +// CIR: %[[LOADED_THIS:.*]] = cir.load %[[THIS_ALLOCA]] +// CIR: cir.store {{.*}}%[[LOADED_THIS]], %[[RETVAL]] +// CIR: cir.const #cir.int<42> +// CIR: %[[LOADED_RET:.*]] = cir.load %[[RETVAL]] +// CIR: cir.return %[[LOADED_RET]] : !cir.ptr<!rec_BasicA> +// CIR: } + +// Constructor & Destructor Inheritance chain: +class Base { +public: + Base(); + ~Base(); +}; + +class Derived : public Base { +public: + Derived(); + ~Derived(); +}; + +Derived::Derived() {} +Derived::~Derived() {} + +// Derived ctor calls Base ctor and returns this: +// CIR-LABEL: cir.func {{.*}} @"??0Derived@@QEAA@XZ" +// CIR-SAME: (%[[THIS:.*]]: !cir.ptr<!rec_Derived>{{.*}}) -> (!cir.ptr<!rec_Derived> +// CIR: cir.call @"??0Base@@QEAA@XZ" +// CIR: cir.return %{{.*}} : !cir.ptr<!rec_Derived> + +// Derived dtor calls Base dtor: +// CIR-LABEL: cir.func {{.*}} @"??1Derived@@QEAA@XZ" +// CIR-SAME: (%[[THIS:.*]]: !cir.ptr<!rec_Derived> +// CIR: cir.call @"??1Base@@QEAA@XZ" + +//===----------------------------------------------------------------------===// +// Section 3: Virtual Functions and Vector/Scalar Deleting Destructors +//===----------------------------------------------------------------------===// + +class Shape { +public: + virtual ~Shape(); + virtual void draw(); +}; + +void call_virtual(Shape *s) { + s->draw(); +} + +// Virtual call uses vtable lookup: +// CIR-LABEL: cir.func {{.*}} @"?call_virtual@@YAXPEAVShape@@@Z" +// CIR-SAME: (%[[ARG:.*]]: !cir.ptr<!rec_Shape>{{.*}}) +// CIR: %[[VPTR:.*]] = cir.vtable.get_vptr +// CIR: %[[VTABLE_PTR:.*]] = cir.load align(8) %[[VPTR]] +// CIR: %[[VFN_SLOT:.*]] = cir.vtable.get_virtual_fn_addr %[[VTABLE_PTR]][1] +// CIR: %[[VFN:.*]] = cir.load align(8) %[[VFN_SLOT]] +// CIR: cir.call %[[VFN]](%{{.*}}) + +void delete_virtual(Shape *s) { + delete s; +} + +// Virtual destructor call triggers vector/scalar deleting destructor (?_E or ?_G) +// with implicit should_call_delete flag passed as an argument: +// CIR-LABEL: cir.func {{.*}} @"?delete_virtual@@YAXPEAVShape@@@Z" +// CIR-SAME: (%[[ARG:.*]]: !cir.ptr<!rec_Shape>{{.*}}) +// CIR: %[[FLAG:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[VPTR:.*]] = cir.vtable.get_vptr +// CIR: %[[VTABLE_PTR:.*]] = cir.load align(8) %[[VPTR]] +// CIR: %[[VFN_SLOT:.*]] = cir.vtable.get_virtual_fn_addr %[[VTABLE_PTR]][0] +// CIR: %[[VFN:.*]] = cir.load align(8) %[[VFN_SLOT]] +// CIR: cir.call %[[VFN]](%{{.*}}, %[[FLAG]]) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
