[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 [email protected] 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
[email protected]
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
[email protected]
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 [email protected] 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 [email protected] 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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
