[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/andykaylor closed https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/143579 >From 844b07e53937d3496405fd2c58148bd03c1f7407 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 9 Jun 2025 09:38:55 -0700 Subject: [PATCH 1/3] [CIR] Upstream support for calling constructors This change adds support for calling C++ constructors. The support for actually defining a constructor is still missing and will be added in a later change. --- clang/include/clang/CIR/MissingFeatures.h | 3 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 99 +-- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 74 ++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 51 ++ clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 6 ++ clang/lib/CIR/CodeGen/CIRGenFunction.h| 13 +++ clang/lib/CIR/CodeGen/CIRGenModule.cpp| 54 +- clang/lib/CIR/CodeGen/CIRGenModule.h | 19 clang/lib/CIR/CodeGen/CIRGenTypes.h | 6 ++ clang/test/CIR/CodeGen/ctor.cpp | 19 10 files changed, 336 insertions(+), 8 deletions(-) create mode 100644 clang/test/CIR/CodeGen/ctor.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 72d882beb2244..f89d386378e51 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -222,6 +222,9 @@ struct MissingFeatures { static bool instrumentation() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cxxRecordStaticMembers() { return false; } + static bool isMemcpyEquivalentSpecialMember() { return false; } + static bool isTrivialCtorOrDtor() { return false; } + static bool implicitConstructorArgs() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index b194a8670bfb9..9d25eea9e413d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,13 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { return *this; } +/// Returns the canonical formal type of the given C++ method. +static CanQual getFormalType(const CXXMethodDecl *md) { + return md->getType() + ->getCanonicalTypeUnqualified() + .getAs(); +} + /// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size_attrs, then we'll add parameters for those, too. /// TODO(cir): this should be shared with LLVM codegen @@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; + + if (auto *cd = dyn_cast(md)) { +// A base class inheriting constructor doesn't get forwarded arguments +// needed to construct a virtual base (or base class thereof) +if (cd->getInheritedConstructor()) + cgm.errorNYI(cd->getSourceRange(), + "arrangeCXXStructorDeclaration: inheriting constructor"); + } + + CanQual fpt = getFormalType(md); + + if (passParams) +appendParameterTypes(*this, argTypes, fpt); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + RequiredArgs required = + (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) + : RequiredArgs::All); + + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(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()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR /// qualification. Either or both of `rd` and `md` may be null. A null `rd` /// indicates that there is no meaningful 'this' type, and a null `md` can occur @@ -103,13 +152,13 @@ CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd, /// top of any implicit parameters already stored. static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, - CanQual ftp) { + CanQual fpt) { assert(!cir::MissingFeatures::opCallFnInfoOpts()); RequiredArgs required = - RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size()); + RequiredArgs::getFromProtoWithExtraSlots(f
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -1393,6 +1393,57 @@ RValue CIRGenFunction::emitCXXMemberCallExpr(const CXXMemberCallExpr *ce, ce, md, returnValue, hasQualifier, qualifier, isArrow, base); } +void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, + AggValueSlot dest) { + assert(!dest.isIgnored() && "Must have a destination!"); + const CXXConstructorDecl *cd = e->getConstructor(); + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now, unless destination is + // already zeroed. + if (e->requiresZeroInitialization() && !dest.isZeroed()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: requires initialization"); +return; + } + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + + // Elide the constructor if we're constructing from a temporary + if (getLangOpts().ElideConstructors && e->isElidable()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: elidable constructor"); +return; + } + + if (const ArrayType *arrayType = getContext().getAsArrayType(e->getType())) { +cgm.errorNYI(e->getSourceRange(), "emitCXXConstructExpr: array type"); +return; + } else { +clang::CXXCtorType type = Ctor_Complete; andykaylor wrote: That's just a clang-tidy warning, right? I was going to say that I'd prefer not to restructure the code that way since the missing code represented by the errorNYI doesn't return in the incubator, but I just looked again, and there is no reason that it couldn't return and that would save a level of indenting on the rest of the code, so I'll go ahead with the suggested change. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -1393,6 +1393,57 @@ RValue CIRGenFunction::emitCXXMemberCallExpr(const CXXMemberCallExpr *ce, ce, md, returnValue, hasQualifier, qualifier, isArrow, base); } +void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, + AggValueSlot dest) { + assert(!dest.isIgnored() && "Must have a destination!"); + const CXXConstructorDecl *cd = e->getConstructor(); + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now, unless destination is + // already zeroed. + if (e->requiresZeroInitialization() && !dest.isZeroed()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: requires initialization"); +return; + } + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + + // Elide the constructor if we're constructing from a temporary + if (getLangOpts().ElideConstructors && e->isElidable()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: elidable constructor"); +return; + } + + if (const ArrayType *arrayType = getContext().getAsArrayType(e->getType())) { AmrDeveloper wrote: NIT: `arrayType` variable will be unused I think it can be ``` if (getContext().getAsArrayType(e->getType())) ``` https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/AmrDeveloper edited https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/AmrDeveloper approved this pull request. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -1393,6 +1393,57 @@ RValue CIRGenFunction::emitCXXMemberCallExpr(const CXXMemberCallExpr *ce, ce, md, returnValue, hasQualifier, qualifier, isArrow, base); } +void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, + AggValueSlot dest) { + assert(!dest.isIgnored() && "Must have a destination!"); + const CXXConstructorDecl *cd = e->getConstructor(); + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now, unless destination is + // already zeroed. + if (e->requiresZeroInitialization() && !dest.isZeroed()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: requires initialization"); +return; + } + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + + // Elide the constructor if we're constructing from a temporary + if (getLangOpts().ElideConstructors && e->isElidable()) { +cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: elidable constructor"); +return; + } + + if (const ArrayType *arrayType = getContext().getAsArrayType(e->getType())) { +cgm.errorNYI(e->getSourceRange(), "emitCXXConstructExpr: array type"); +return; + } else { +clang::CXXCtorType type = Ctor_Complete; AmrDeveloper wrote: NIT: To eliminate “Do not use else after return” warning, should we remove the else branch? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/143579 >From 844b07e53937d3496405fd2c58148bd03c1f7407 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 9 Jun 2025 09:38:55 -0700 Subject: [PATCH 1/2] [CIR] Upstream support for calling constructors This change adds support for calling C++ constructors. The support for actually defining a constructor is still missing and will be added in a later change. --- clang/include/clang/CIR/MissingFeatures.h | 3 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 99 +-- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 74 ++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 51 ++ clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 6 ++ clang/lib/CIR/CodeGen/CIRGenFunction.h| 13 +++ clang/lib/CIR/CodeGen/CIRGenModule.cpp| 54 +- clang/lib/CIR/CodeGen/CIRGenModule.h | 19 clang/lib/CIR/CodeGen/CIRGenTypes.h | 6 ++ clang/test/CIR/CodeGen/ctor.cpp | 19 10 files changed, 336 insertions(+), 8 deletions(-) create mode 100644 clang/test/CIR/CodeGen/ctor.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 72d882beb2244..f89d386378e51 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -222,6 +222,9 @@ struct MissingFeatures { static bool instrumentation() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cxxRecordStaticMembers() { return false; } + static bool isMemcpyEquivalentSpecialMember() { return false; } + static bool isTrivialCtorOrDtor() { return false; } + static bool implicitConstructorArgs() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index b194a8670bfb9..9d25eea9e413d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,13 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { return *this; } +/// Returns the canonical formal type of the given C++ method. +static CanQual getFormalType(const CXXMethodDecl *md) { + return md->getType() + ->getCanonicalTypeUnqualified() + .getAs(); +} + /// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size_attrs, then we'll add parameters for those, too. /// TODO(cir): this should be shared with LLVM codegen @@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; + + if (auto *cd = dyn_cast(md)) { +// A base class inheriting constructor doesn't get forwarded arguments +// needed to construct a virtual base (or base class thereof) +if (cd->getInheritedConstructor()) + cgm.errorNYI(cd->getSourceRange(), + "arrangeCXXStructorDeclaration: inheriting constructor"); + } + + CanQual fpt = getFormalType(md); + + if (passParams) +appendParameterTypes(*this, argTypes, fpt); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + RequiredArgs required = + (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) + : RequiredArgs::All); + + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(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()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR /// qualification. Either or both of `rd` and `md` may be null. A null `rd` /// indicates that there is no meaningful 'this' type, and a null `md` can occur @@ -103,13 +152,13 @@ CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd, /// top of any implicit parameters already stored. static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, - CanQual ftp) { + CanQual fpt) { assert(!cir::MissingFeatures::opCallFnInfoOpts()); RequiredArgs required = - RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size()); + RequiredArgs::getFromProtoWithExtraSlots(f
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -63,3 +66,74 @@ Address CIRGenFunction::getAddressOfBaseClass( return value; } + +void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, +clang::CXXCtorType type, +bool forVirtualBase, +bool delegating, +AggValueSlot thisAVS, +const clang::CXXConstructExpr *e) { + CallArgList args; + Address thisAddr = thisAVS.getAddress(); + QualType thisType = d->getThisType(); + mlir::Value thisPtr = thisAddr.getPointer(); + + assert(!cir::MissingFeatures::addressSpace()); + + args.add(RValue::get(thisPtr), thisType); + + // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. + // If this is a union copy constructor, we must emit a memcpy, because the AST + // does not model that copy. + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + const FunctionProtoType *fpt = d->getType()->castAs(); + + assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); + + emitCallArgs(args, fpt, e->arguments(), e->getConstructor(), + /*ParamsToSkip=*/0); + + assert(!cir::MissingFeatures::sanitizers()); + emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, + e->getExprLoc()); +} + +void CIRGenFunction::emitCXXConstructorCall( +const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, +bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { + + const auto *cd = d->getParent(); + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + assert(!cir::MissingFeatures::isTrivialCtorOrDtor()); + + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + bool passPrototypeArgs = true; erichkeane wrote: Can we set this anyway? Alternatively, just set it to `!d->getInheritedConstructor`? Its at least easier here, since we don't need a cast to get the info we need. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -141,6 +190,44 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, return cgt.arrangeCIRFunctionInfo(retType, argTypes, required); } +/// Arrange a call to a C++ method, passing the given arguments. +/// +/// passProtoArgs indicates whether `args` has args for the parameters in the +/// given CXXConstructorDecl. +const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( +const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind, +bool passProtoArgs) { + + // FIXME: Kill copy. erichkeane wrote: Ah... Its kind of frustrating to see these FIXME's last as long as they do, then get propagated into the new lowering like this. I guess I can live with it (as we have for years), but we gotta stop letting these FIXMEs last as long as they do:/ https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; erichkeane wrote: Ah, hrmph... Can we set it there ANYWAY, despite doing an NYI? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; andykaylor wrote: It will be set to false by the code that is missing on line 99. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -63,3 +66,74 @@ Address CIRGenFunction::getAddressOfBaseClass( return value; } + +void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, +clang::CXXCtorType type, +bool forVirtualBase, +bool delegating, +AggValueSlot thisAVS, +const clang::CXXConstructExpr *e) { + CallArgList args; + Address thisAddr = thisAVS.getAddress(); + QualType thisType = d->getThisType(); + mlir::Value thisPtr = thisAddr.getPointer(); + + assert(!cir::MissingFeatures::addressSpace()); + + args.add(RValue::get(thisPtr), thisType); + + // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. + // If this is a union copy constructor, we must emit a memcpy, because the AST + // does not model that copy. + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + const FunctionProtoType *fpt = d->getType()->castAs(); + + assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); + + emitCallArgs(args, fpt, e->arguments(), e->getConstructor(), + /*ParamsToSkip=*/0); + + assert(!cir::MissingFeatures::sanitizers()); + emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, + e->getExprLoc()); +} + +void CIRGenFunction::emitCXXConstructorCall( +const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, +bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { + + const auto *cd = d->getParent(); + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + assert(!cir::MissingFeatures::isTrivialCtorOrDtor()); + + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + bool passPrototypeArgs = true; andykaylor wrote: This will be set by the missing code on line 120. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -141,6 +190,44 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, return cgt.arrangeCIRFunctionInfo(retType, argTypes, required); } +/// Arrange a call to a C++ method, passing the given arguments. +/// +/// passProtoArgs indicates whether `args` has args for the parameters in the +/// given CXXConstructorDecl. +const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( +const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind, +bool passProtoArgs) { + + // FIXME: Kill copy. andykaylor wrote: This is one of those comments that was brought over from classic codegen. It appears six times in both classic codegen and the CIR incubator codegen, always in conjunction with a call to arrangeLLVMFunctionInfo/arrangeCIRFunctionInfo. The problem is that one of the places it occurs (the static version of arrangeLLVMFunctionInfo/arrangeCIRFunctionInfo) takes a list of types from the caller but then appends additional types based on FunctionProtoType::getExtParameterInfos(). I definitely want to leave it alone for now. It may be a solvable problem, but the priority of solving it appears to be very low. https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -63,3 +66,74 @@ Address CIRGenFunction::getAddressOfBaseClass( return value; } + +void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, +clang::CXXCtorType type, +bool forVirtualBase, +bool delegating, +AggValueSlot thisAVS, +const clang::CXXConstructExpr *e) { + CallArgList args; + Address thisAddr = thisAVS.getAddress(); + QualType thisType = d->getThisType(); + mlir::Value thisPtr = thisAddr.getPointer(); + + assert(!cir::MissingFeatures::addressSpace()); + + args.add(RValue::get(thisPtr), thisType); + + // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. + // If this is a union copy constructor, we must emit a memcpy, because the AST + // does not model that copy. + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + const FunctionProtoType *fpt = d->getType()->castAs(); + + assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); + + emitCallArgs(args, fpt, e->arguments(), e->getConstructor(), + /*ParamsToSkip=*/0); + + assert(!cir::MissingFeatures::sanitizers()); + emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, + e->getExprLoc()); +} + +void CIRGenFunction::emitCXXConstructorCall( +const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, +bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { + + const auto *cd = d->getParent(); + + // If this is a call to a trivial default constructor: + // In LLVM: do nothing. + // In CIR: emit as a regular call, other later passes should lower the + // ctor call into trivial initialization. + assert(!cir::MissingFeatures::isTrivialCtorOrDtor()); + + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + bool passPrototypeArgs = true; erichkeane wrote: Read, but never set? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -141,6 +190,44 @@ arrangeFreeFunctionLikeCall(CIRGenTypes &cgt, CIRGenModule &cgm, return cgt.arrangeCIRFunctionInfo(retType, argTypes, required); } +/// Arrange a call to a C++ method, passing the given arguments. +/// +/// passProtoArgs indicates whether `args` has args for the parameters in the +/// given CXXConstructorDecl. +const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( +const CallArgList &args, const CXXConstructorDecl *d, CXXCtorType ctorKind, +bool passProtoArgs) { + + // FIXME: Kill copy. erichkeane wrote: The only idea I have for us to do something like this, would be to have `arrangeCIRFunctionInfo` to have a optional `arg-transform` function. So it becomes: `arrangeCIRFunctionInfo(resultType, argTypes, [&](auto *arg) { astContext.getCanonicalParamType(arg.ty);});` Alternatively, have it take some sort of mutating range, which does the work for us? Or maybe build that into CallArgList, and have `arrangeCIRFunctionInfo` take a `CallArgList` and use a `arg.getCanonicalParamType()` on CallArg's object. WDYT? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -63,3 +66,74 @@ Address CIRGenFunction::getAddressOfBaseClass( return value; } + +void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d, +clang::CXXCtorType type, +bool forVirtualBase, +bool delegating, +AggValueSlot thisAVS, +const clang::CXXConstructExpr *e) { + CallArgList args; + Address thisAddr = thisAVS.getAddress(); + QualType thisType = d->getThisType(); + mlir::Value thisPtr = thisAddr.getPointer(); + + assert(!cir::MissingFeatures::addressSpace()); + + args.add(RValue::get(thisPtr), thisType); + + // In LLVM Codegen: If this is a trivial constructor, just emit what's needed. + // If this is a union copy constructor, we must emit a memcpy, because the AST + // does not model that copy. + assert(!cir::MissingFeatures::isMemcpyEquivalentSpecialMember()); + + const FunctionProtoType *fpt = d->getType()->castAs(); + + assert(!cir::MissingFeatures::opCallArgEvaluationOrder()); + + emitCallArgs(args, fpt, e->arguments(), e->getConstructor(), + /*ParamsToSkip=*/0); + + assert(!cir::MissingFeatures::sanitizers()); + emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args, + e->getExprLoc()); +} + +void CIRGenFunction::emitCXXConstructorCall( +const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, +bool delegating, Address thisAddr, CallArgList &args, SourceLocation loc) { + + const auto *cd = d->getParent(); erichkeane wrote: Don't use auto here? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
@@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; erichkeane wrote: I see this is checked, but never set to false? https://github.com/llvm/llvm-project/pull/143579 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for calling constructors (PR #143579)
https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/143579 This change adds support for calling C++ constructors. The support for actually defining a constructor is still missing and will be added in a later change. >From 844b07e53937d3496405fd2c58148bd03c1f7407 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 9 Jun 2025 09:38:55 -0700 Subject: [PATCH] [CIR] Upstream support for calling constructors This change adds support for calling C++ constructors. The support for actually defining a constructor is still missing and will be added in a later change. --- clang/include/clang/CIR/MissingFeatures.h | 3 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 99 +-- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 74 ++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 51 ++ clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 6 ++ clang/lib/CIR/CodeGen/CIRGenFunction.h| 13 +++ clang/lib/CIR/CodeGen/CIRGenModule.cpp| 54 +- clang/lib/CIR/CodeGen/CIRGenModule.h | 19 clang/lib/CIR/CodeGen/CIRGenTypes.h | 6 ++ clang/test/CIR/CodeGen/ctor.cpp | 19 10 files changed, 336 insertions(+), 8 deletions(-) create mode 100644 clang/test/CIR/CodeGen/ctor.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 72d882beb2244..f89d386378e51 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -222,6 +222,9 @@ struct MissingFeatures { static bool instrumentation() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cxxRecordStaticMembers() { return false; } + static bool isMemcpyEquivalentSpecialMember() { return false; } + static bool isTrivialCtorOrDtor() { return false; } + static bool implicitConstructorArgs() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index b194a8670bfb9..9d25eea9e413d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,13 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { return *this; } +/// Returns the canonical formal type of the given C++ method. +static CanQual getFormalType(const CXXMethodDecl *md) { + return md->getType() + ->getCanonicalTypeUnqualified() + .getAs(); +} + /// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size_attrs, then we'll add parameters for those, too. /// TODO(cir): this should be shared with LLVM codegen @@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; + + if (auto *cd = dyn_cast(md)) { +// A base class inheriting constructor doesn't get forwarded arguments +// needed to construct a virtual base (or base class thereof) +if (cd->getInheritedConstructor()) + cgm.errorNYI(cd->getSourceRange(), + "arrangeCXXStructorDeclaration: inheriting constructor"); + } + + CanQual fpt = getFormalType(md); + + if (passParams) +appendParameterTypes(*this, argTypes, fpt); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + RequiredArgs required = + (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) + : RequiredArgs::All); + + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(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()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR /// qualification. Either or both of `rd` and `md` may be null. A null `rd` /// indicates that there is no meaningful 'this' type, and a null `md` can occur @@ -103,13 +152,13 @@ CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd, /// top of any implicit parameters already stored. static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, - CanQual ftp) { + CanQual fpt) { assert(!cir::MissingFeatures::opCallFnInf
[clang] [CIR] Upstream support for calling constructors (PR #143579)
llvmbot wrote: @llvm/pr-subscribers-clangir Author: Andy Kaylor (andykaylor) Changes This change adds support for calling C++ constructors. The support for actually defining a constructor is still missing and will be added in a later change. --- Patch is 22.10 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/143579.diff 10 Files Affected: - (modified) clang/include/clang/CIR/MissingFeatures.h (+3) - (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+93-6) - (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+74) - (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+51) - (modified) clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp (+6) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+13) - (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+52-2) - (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+19) - (modified) clang/lib/CIR/CodeGen/CIRGenTypes.h (+6) - (added) clang/test/CIR/CodeGen/ctor.cpp (+19) ``diff diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 72d882beb2244..f89d386378e51 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -222,6 +222,9 @@ struct MissingFeatures { static bool instrumentation() { return false; } static bool cleanupAfterErrorDiags() { return false; } static bool cxxRecordStaticMembers() { return false; } + static bool isMemcpyEquivalentSpecialMember() { return false; } + static bool isTrivialCtorOrDtor() { return false; } + static bool implicitConstructorArgs() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index b194a8670bfb9..9d25eea9e413d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -60,6 +60,13 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { return *this; } +/// Returns the canonical formal type of the given C++ method. +static CanQual getFormalType(const CXXMethodDecl *md) { + return md->getType() + ->getCanonicalTypeUnqualified() + .getAs(); +} + /// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size_attrs, then we'll add parameters for those, too. /// TODO(cir): this should be shared with LLVM codegen @@ -76,6 +83,48 @@ static void appendParameterTypes(const CIRGenTypes &cgt, cgt.getCGModule().errorNYI("appendParameterTypes: hasExtParameterInfos"); } +const CIRGenFunctionInfo & +CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { + auto *md = cast(gd.getDecl()); + + llvm::SmallVector argTypes; + argTypes.push_back(deriveThisType(md->getParent(), md)); + + bool passParams = true; + + if (auto *cd = dyn_cast(md)) { +// A base class inheriting constructor doesn't get forwarded arguments +// needed to construct a virtual base (or base class thereof) +if (cd->getInheritedConstructor()) + cgm.errorNYI(cd->getSourceRange(), + "arrangeCXXStructorDeclaration: inheriting constructor"); + } + + CanQual fpt = getFormalType(md); + + if (passParams) +appendParameterTypes(*this, argTypes, fpt); + + assert(!cir::MissingFeatures::implicitConstructorArgs()); + + RequiredArgs required = + (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) + : RequiredArgs::All); + + CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + : theCXXABI.hasMostDerivedReturn(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()); + + return arrangeCIRFunctionInfo(resultType, argTypes, required); +} + /// Derives the 'this' type for CIRGen purposes, i.e. ignoring method CVR /// qualification. Either or both of `rd` and `md` may be null. A null `rd` /// indicates that there is no meaningful 'this' type, and a null `md` can occur @@ -103,13 +152,13 @@ CanQualType CIRGenTypes::deriveThisType(const CXXRecordDecl *rd, /// top of any implicit parameters already stored. static const CIRGenFunctionInfo & arrangeCIRFunctionInfo(CIRGenTypes &cgt, SmallVectorImpl &prefix, - CanQual ftp) { + CanQual fpt) { assert(!cir::MissingFeatures::opCallFnInfoOpts()); RequiredArgs required = - RequiredArgs::getFromProtoWithExtraSlots(ftp, prefix.size()); + RequiredArgs::getFromProtoWithExtraSlots(fpt, prefix.size()); assert(!cir::MissingFeatures::opCallExtParameterInfo()); - appendParameterTypes(cgt, prefix, ftp); - CanQualType resultType = ftp->g