-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CIR] Upstream support for calling constructors #143579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,13 @@ CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { | |
return *this; | ||
} | ||
|
||
/// Returns the canonical formal type of the given C++ method. | ||
static CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *md) { | ||
return md->getType() | ||
->getCanonicalTypeUnqualified() | ||
.getAs<FunctionProtoType>(); | ||
} | ||
|
||
/// 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<CXXMethodDecl>(gd.getDecl()); | ||
|
||
llvm::SmallVector<CanQualType, 16> argTypes; | ||
argTypes.push_back(deriveThisType(md->getParent(), md)); | ||
|
||
bool passParams = true; | ||
|
||
if (auto *cd = dyn_cast<CXXConstructorDecl>(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<FunctionProtoType> 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<CanQualType> &prefix, | ||
CanQual<FunctionProtoType> ftp) { | ||
CanQual<FunctionProtoType> 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->getReturnType().getUnqualifiedType(); | ||
appendParameterTypes(cgt, prefix, fpt); | ||
CanQualType resultType = fpt->getReturnType().getUnqualifiedType(); | ||
return cgt.arrangeCIRFunctionInfo(resultType, prefix, required); | ||
} | ||
|
||
|
@@ -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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only idea I have for us to do something like this, would be to have
Alternatively, have it take some sort of mutating range, which does the work for us? Or maybe build that into CallArgList, and have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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:/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. We've been following the practice of using "TODO(cir)" when we introduce new placeholders like this in the CIR code so we can distinguish them from TODOs that we copied over from classic codegen, but I expect that they'll have the same problem if we don't do something about it. |
||
llvm::SmallVector<CanQualType, 16> argTypes; | ||
for (const auto &arg : args) | ||
argTypes.push_back(astContext.getCanonicalParamType(arg.ty)); | ||
|
||
assert(!cir::MissingFeatures::implicitConstructorArgs()); | ||
// +1 for implicit this, which should always be args[0] | ||
unsigned totalPrefixArgs = 1; | ||
|
||
CanQual<FunctionProtoType> fpt = getFormalType(d); | ||
RequiredArgs required = | ||
passProtoArgs | ||
? RequiredArgs::getFromProtoWithExtraSlots(fpt, totalPrefixArgs) | ||
: 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; | ||
|
||
assert(!cir::MissingFeatures::opCallFnInfoOpts()); | ||
assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); | ||
|
||
return arrangeCIRFunctionInfo(resultType, argTypes, required); | ||
} | ||
|
||
/// Arrange a call to a C++ method, passing the given arguments. | ||
/// | ||
/// numPrefixArgs is the number of the ABI-specific prefix arguments we have. It | ||
|
@@ -198,7 +285,7 @@ CIRGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *md) { | |
/// constructor or destructor. | ||
const CIRGenFunctionInfo & | ||
CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd, | ||
const FunctionProtoType *ftp, | ||
const FunctionProtoType *fpt, | ||
const CXXMethodDecl *md) { | ||
llvm::SmallVector<CanQualType, 16> argTypes; | ||
|
||
|
@@ -208,7 +295,7 @@ CIRGenTypes::arrangeCXXMethodType(const CXXRecordDecl *rd, | |
assert(!cir::MissingFeatures::opCallFnInfoOpts()); | ||
return ::arrangeCIRFunctionInfo( | ||
*this, argTypes, | ||
ftp->getCanonicalTypeUnqualified().getAs<FunctionProtoType>()); | ||
fpt->getCanonicalTypeUnqualified().getAs<FunctionProtoType>()); | ||
} | ||
|
||
/// Arrange the argument and result information for the declaration or | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,9 +10,12 @@ | |
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "CIRGenCXXABI.h" | ||
#include "CIRGenFunction.h" | ||
|
||
#include "clang/AST/ExprCXX.h" | ||
#include "clang/AST/RecordLayout.h" | ||
#include "clang/AST/Type.h" | ||
#include "clang/CIR/MissingFeatures.h" | ||
|
||
using namespace clang; | ||
|
@@ -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<FunctionProtoType>(); | ||
|
||
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 CXXRecordDecl *crd = 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Read, but never set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be set by the missing code on line 120. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we set this anyway? Alternatively, just set it to |
||
|
||
// Check whether we can actually emit the constructor before trying to do so. | ||
if (d->getInheritedConstructor()) { | ||
cgm.errorNYI(d->getSourceRange(), | ||
"emitCXXConstructorCall: inherited constructor"); | ||
return; | ||
} | ||
|
||
// Insert any ABI-specific implicit constructor arguments. | ||
assert(!cir::MissingFeatures::implicitConstructorArgs()); | ||
|
||
// Emit the call. | ||
auto calleePtr = cgm.getAddrOfCXXStructor(GlobalDecl(d, type)); | ||
const CIRGenFunctionInfo &info = cgm.getTypes().arrangeCXXConstructorCall( | ||
args, d, type, passPrototypeArgs); | ||
CIRGenCallee callee = CIRGenCallee::forDirect(calleePtr, GlobalDecl(d, type)); | ||
cir::CIRCallOpInterface c; | ||
emitCall(info, callee, ReturnValueSlot(), args, &c, getLoc(loc)); | ||
|
||
if (cgm.getCodeGenOpts().OptimizationLevel != 0 && !crd->isDynamicClass() && | ||
type != Ctor_Base && cgm.getCodeGenOpts().StrictVTablePointers) | ||
cgm.errorNYI(d->getSourceRange(), "vtable assumption loads"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is checked, but never set to false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be set to false by the code that is missing on line 99.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, hrmph... Can we set it there ANYWAY, despite doing an NYI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be set to the result of a function call in the final implementation. I can add a line to just set it to false there as a place holder if you think that's useful. Same for the other similar case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah! Oh, I missed that it is still calculated below. Lets skip it for now then, how you have now LGTM.