https://github.com/R-Goc updated https://github.com/llvm/llvm-project/pull/233291
>From fc8cfd5909a0419209df33877767bf80de7a8ca1 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 | 184 ++++++++---------- 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 | 72 ++++++- 11 files changed, 222 insertions(+), 144 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 2d9113c2789933..b6edbfa8ec45f9 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 bcf301a0b5ae20..3e3bb7733a9c13 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 f30a8be15bc2bb..8d13f92b952cf6 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 e5f20f7dec01d1..028a4e04d119a5 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 b866b1ee554bf9..fd4cc55c1d2dce 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,9 +17,14 @@ #include "CIRGenFunction.h" #include "CIRGenModule.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Mangle.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::CIRGen; @@ -27,23 +35,71 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { public: CIRGenMicrosoftCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {} + bool hasThisReturn(GlobalDecl gd) const override { + return isa<CXXConstructorDecl>(gd.getDecl()); + } + + bool hasMostDerivedReturn(GlobalDecl gd) const override { return false; } + + StringRef getPureVirtualCallName() override { return "_purecall"; } + 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 false; + } + + bool isZeroInitializable(const MemberPointerType *mpt) override { + return true; + } + + CharUnits getArrayCookieSizeImpl(QualType elementType) override { + return CharUnits::Zero(); + } + + 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 setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd, + bool returnAdjustment) override { + cgm.errorNYI("setThunkLinkage: MSVC ABI"); + } + AddedStructorArgCounts buildStructorSignature(GlobalDecl gd, SmallVectorImpl<CanQualType> &argTys) override { - cgm.errorNYI(gd.getDecl()->getSourceRange(), - "buildStructorSignature: MSVC ABI"); return AddedStructorArgCounts{}; } 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"); + if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) + return; + + mlir::Value thisVal = loadIncomingCXXThis(cgf); + setCXXABIThisValue(cgf, thisVal); + + if (hasThisReturn(cgf.curGD)) { + if (cgf.returnValue.isValid()) + cgf.getBuilder().createStore(cgf.getLoc(loc), thisVal, cgf.returnValue); + } } AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf, @@ -51,8 +107,6 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { CXXCtorType type, bool forVirtualBase, bool delegating) override { - cgf.cgm.errorNYI(d->getSourceRange(), - "getImplicitConstructorArgs: MSVC ABI"); return AddedStructorArgs{}; } @@ -61,13 +115,11 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { 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"); + cgm.emitGlobal(GlobalDecl(d, Ctor_Complete)); } void emitCXXDestructors(const CXXDestructorDecl *d) override { @@ -75,6 +127,11 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { } void emitCXXStructor(GlobalDecl gd) override { + if (auto *ctor = dyn_cast<CXXConstructorDecl>(gd.getDecl())) { + auto fn = cgm.codegenCXXStructor(gd.getWithCtorType(Ctor_Complete)); + cgm.maybeSetTrivialComdat(*ctor, fn); + return; + } cgm.errorNYI(gd.getDecl()->getSourceRange(), "emitCXXStructor: MSVC ABI"); } @@ -102,36 +159,16 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { 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 - // has v-bases. - if (cd->getParent()->getNumVBases() > 0 && - cd->getType()->castAs<FunctionProtoType>()->isVariadic()) - return 2; return 1; } const CXXRecordDecl * getThisArgumentTypeForMethod(const CXXMethodDecl *md) override { - cgm.errorNYI(md->getSourceRange(), - "getThisArgumentTypeForMethod: MSVC ABI"); return md->getParent(); } - Address adjustThisArgumentForVirtualFunctionCall(CIRGenFunction &cgf, - GlobalDecl gd, - Address thisAddr, - bool virtualCall) override { - cgf.cgm.errorNYI(gd.getDecl()->getSourceRange(), - "adjustThisArgumentForVirtualFunctionCall: MSVC ABI"); - return thisAddr; - } - bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) override { - cgf.cgm.errorNYI("isVirtualOffsetNeededForVTableField: MSVC ABI"); return false; } @@ -181,13 +218,6 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { "emitVirtualInheritanceTables: MSVC ABI"); } - void - initializeHiddenVirtualInheritanceMembers(CIRGenFunction &cgf, - const CXXRecordDecl *rd) override { - cgf.cgm.errorNYI(rd->getSourceRange(), - "initializeHiddenVirtualInheritanceMembers: MSVC ABI"); - } - mlir::Value getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf, Address thisAddr, const CXXRecordDecl *classDecl, @@ -199,7 +229,7 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { cir::MethodAttr buildVirtualMethodAttr(cir::MethodType methodTy, const CXXMethodDecl *md) override { cgm.errorNYI(md->getSourceRange(), "buildVirtualMethodAttr: MSVC ABI"); - return cir::MethodAttr(); + return {}; } mlir::Value performThisAdjustment(CIRGenFunction &cgf, Address thisAddr, @@ -216,65 +246,12 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { return ret.emitRawPointer(); } - bool canSpeculativelyEmitVTable(const CXXRecordDecl *rd) const override { - return false; - } - - bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override { - cgm.errorNYI(vtableClass->getSourceRange(), - "doStructorsInitializeVPtrs: MSVC ABI"); - return false; - } - - bool exportThunk() override { return false; } - - bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, - CXXDtorType dt) const override { - cgm.errorNYI(dtor->getSourceRange(), "useThunkForDtorVariant: MSVC ABI"); - return false; - } - - void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd, - bool returnAdjustment) override { - cgm.errorNYI(gd.getDecl()->getSourceRange(), "setThunkLinkage: MSVC ABI"); - } - - StringRef getPureVirtualCallName() override { return "_purecall"; } - StringRef getDeletedVirtualCallName() override { return "_purecall"; } - - bool isZeroInitializable(const MemberPointerType *mpt) override { - cgm.errorNYI("isZeroInitializable: MSVC ABI"); - return true; - } - - bool requiresArrayCookie(const CXXNewExpr *e) override { - cgm.errorNYI(e->getSourceRange(), "requiresArrayCookie: MSVC ABI"); - return false; - } - - CharUnits getArrayCookieSizeImpl(QualType elementType) override { - cgm.errorNYI("getArrayCookieSizeImpl: MSVC ABI"); - return CharUnits::Zero(); - } - - 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; - } - - bool shouldTypeidBeNullChecked(QualType srcTy) override { - cgm.errorNYI("shouldTypeidBeNullChecked: MSVC ABI"); - return false; - } + bool shouldTypeidBeNullChecked(QualType srcTy) override { return false; } 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())); + cgf.cgm.errorNYI("emitTypeid: MSVC ABI"); + return nullptr; } void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override { @@ -282,7 +259,7 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { } void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override { - cgm.errorNYI(loc, "emitBadCastCall: MSVC ABI"); + cgf.cgm.errorNYI(loc, "emitBadCastCall: MSVC ABI"); } mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc, @@ -299,20 +276,15 @@ class CIRGenMicrosoftCXXABI : public CIRGenCXXABI { return nullptr; } - CatchTypeInfo getCatchAllTypeInfo() override { - cgm.errorNYI("getCatchAllTypeInfo: MSVC ABI"); - return CatchTypeInfo{nullptr, 0}; - } - CatchTypeInfo getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty, QualType catchHandlerType) override { cgm.errorNYI(loc, "getAddrOfCXXCatchHandlerType: MSVC ABI"); - return CatchTypeInfo{nullptr, 0}; + return {}; } void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override { - cgm.errorNYI("emitRethrow: MSVC ABI"); + cgf.cgm.errorNYI("emitRethrow: MSVC ABI"); } void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override { diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 8801a730e8d678..3f81658f45c627 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2185,7 +2185,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()); @@ -2200,8 +2200,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); @@ -2253,27 +2253,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; @@ -2914,9 +2925,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); } } @@ -3752,12 +3764,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 074ca5818ae2ee..baa0342a4ab82b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -595,6 +595,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 d2f1b54e43325c..a9e19b123baf63 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -163,8 +163,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..8fea5651a186af 100644 --- a/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp +++ b/clang/test/CIR/CodeGen/cxx-msvc-abi.cpp @@ -1,6 +1,74 @@ // 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; } +}; + +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(); +}; + +class Derived : public Base { +public: + 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> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
